﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using MacomberMapSystem.Common.Database;
using MacomberMapSystem.Common.CIM;
using MacomberMapSystem.Common.Serialization;
using MacomberMapSystem.Common.Integration;
using System.Drawing.Drawing2D;
using MacomberMapSystem.Common.Exports;
using MacomberMapSystem.Common.Internals;
using System.Windows.Forms.VisualStyles;
using System.IO;
using System.Drawing.Imaging;

namespace MacomberMapSystem.Common.User_Interfaces.One_Lines
{
    /// <summary>
    /// This class holds information on a one-line element
    /// </summary>
    public partial class MM_OneLine_Element : UserControl
    {
        #region Variable declarations
        /// <summary>Our override to make lines thicker</summary>
        public static float ThicknessOverride = 1f;

        /// <summary>Whether the one-line is to be exported in white-background mode</summary>
        public static bool WhiteBackground = false;

        /// <summary>The collection of analogs to be searched for</summary>
        private static string[] Analogs = new string[] { "MW", "MVAR", "AVR", "PSS", "TAP", "KV", "SAMP" };

        /// <summary>The collection of analogs to be searched for</summary>
        private static string[] UnitAnalogs = new string[] { "MW", "GMV", "AVR", "PSS", "TAP", "KV", "SAMP" };

        /// <summary>The collection of analogs to be searched for when dealing with PUN equipment</summary>
        private static string[] PUNAnalogs = new string[] { "MW", "MVAR", "GMW", "GMV", "AVR", "PSS", "TAP", "KV", "SAMP" };
        #endregion

        #region Enumerations   
        
        /// <summary>
        /// The collection of approved orientations for our current element type
        /// </summary>
        /// <param name="ElementType"></param>
        /// <param name="SubstationShunt">Whether the element is in a substation one-line, or if a compensator, the shunt variety.</param>
        /// <returns></returns>        
        public static enumOrientations[] AllowedOrientations(enumElemTypes ElementType, bool SubstationShunt)
        {
            switch (ElementType)
            {
                case enumElemTypes.None:
                case enumElemTypes.Image:
                case enumElemTypes.Descriptor:
                case enumElemTypes.SecondaryDescriptor:
                case enumElemTypes.Label:
                case enumElemTypes.Circle:
                case enumElemTypes.Rectangle:
                case enumElemTypes.EndCap:
                case enumElemTypes.ArrowLine:
                    return new enumOrientations[] { enumOrientations.Unknown };
                case enumElemTypes.Breaker:
                case enumElemTypes.Switch:
                    if (SubstationShunt)
                        return new enumOrientations[] { enumOrientations.Horizontal, enumOrientations.Vertical };
                    else
                        return new enumOrientations[] { enumOrientations.Horizontal, enumOrientations.Vertical, enumOrientations.Left, enumOrientations.Up, enumOrientations.Right, enumOrientations.Down };
                case enumElemTypes.Transformer:
                    return new enumOrientations[] { enumOrientations.Horizontal, enumOrientations.Vertical };
                case enumElemTypes.Capacitor:
                case enumElemTypes.Reactor:
                case enumElemTypes.Resistor:
                case enumElemTypes.ResistorReactor:
                case enumElemTypes.ResistorCapacitor:
                case enumElemTypes.Line:
                    if (SubstationShunt)
                        return new enumOrientations[] { enumOrientations.Left, enumOrientations.Up, enumOrientations.Right, enumOrientations.Down };
                    else
                        return new enumOrientations[] { enumOrientations.Horizontal, enumOrientations.Vertical};
                case enumElemTypes.Unit:
                case enumElemTypes.Load:
                case enumElemTypes.LAAR:                
                case enumElemTypes.StaticVarCompensator:
                case enumElemTypes.PricingVector:
                    return new enumOrientations[] { enumOrientations.Left, enumOrientations.Up, enumOrientations.Right, enumOrientations.Down };
                case enumElemTypes.Node:
                case enumElemTypes.PokePoint:
                    return new enumOrientations[] { enumOrientations.Unknown, enumOrientations.Horizontal, enumOrientations.Vertical };
                default:
                    throw new InvalidOperationException("Unable to determine orientation for element type " + ElementType.ToString());
            }
        }


        /// <summary>
        /// The collection of element types
        /// </summary>     
        public enum enumElemTypes
        {
            /// <summary>No elements</summary>
            None,
            /// <summary>An image</summary>
            Image,
            /// <summary>A transformer</summary>
            Transformer,
            /// <summary>A primary descriptor</summary>
            Descriptor,
            /// <summary>A secondary descriptor (resource node name)</summary>
            SecondaryDescriptor,
            /// <summary>A circuit breaker</summary>
            Breaker,
            /// <summary>A disconnector</summary>
            Switch,
            /// <summary>A generating unit</summary>
            Unit,
            /// <summary>A transmission line</summary>
            Line,
            /// <summary>A reactor</summary>
            Reactor,
            /// <summary>A reactor</summary>
            Load,
            /// <summary>A load acting as a resource (LaaR)</summary>
            LAAR,
            /// <summary>An end cap</summary>
            EndCap,
            /// <summary>A capacitor</summary>
            Capacitor,
            /// <summary>A static var compensator</summary>
            StaticVarCompensator,
            /// <summary>A node</summary>
            Node,
            /// <summary>A poke point</summary>
            PokePoint,
            /// <summary>A pricing vector</summary>
            PricingVector,
            /// <summary>A static label</summary>
            Label,
            /// <summary>A circle with no element linkage</summary>
            Circle,
            /// <summary>A rectangle</summary>
            Rectangle,
            /// <summary>A resistor</summary>
            Resistor,
            /// <summary>A component with resistance and reactance</summary>
            ResistorReactor,
            /// <summary>A component with resistance and capacitance</summary>
            ResistorCapacitor,
            /// <summary>A line with an arrow</summary>
            ArrowLine,
            /// <summary>A RAS status panel</summary>
            RAS_Status_Panel
        }

        /// <summary>The possible orientations for attributes of the element</summary>
        public enum enumOrientations
        {
            /// <summary>Unknown orientation</summary>
            Unknown,
            /// <summary>Upward orientation</summary>
            Up,
            /// <summary>Downward orientation</summary>
            Down,
            /// <summary>Leftward orientation</summary>
            Left,
            /// <summary>Rightward orientation</summary>
            Right,
            /// <summary>Horizontal orientation</summary>
            Horizontal,
            /// <summary>Vertical orientation</summary>
            Vertical
        };
        #endregion

        #region Static drawing
        /// <summary>
        /// Determine the center of a rectangle
        /// </summary>
        /// <param name="Rect"></param>
        /// <returns></returns>
        public static Point CenterRect(Rectangle Rect)
        {
            return new Point(Rect.Left + (Rect.Width / 2), Rect.Top + (Rect.Height / 2));

        }

        /// <summary>The string format that makes text centered</summary>
        public static StringFormat CenterFormat
        {
            get
            {
                if (_CenterFormat == null)
                {
                    _CenterFormat = new StringFormat(StringFormatFlags.FitBlackBox | StringFormatFlags.NoClip | StringFormatFlags.NoWrap);
                    _CenterFormat.Alignment = _CenterFormat.LineAlignment = StringAlignment.Center;
                    _CenterFormat.Trimming = StringTrimming.None;
                }
                return _CenterFormat;
            }
        }
        private static StringFormat _CenterFormat;


        /// <summary>
        /// Convert a series of integers into a series of points
        /// </summary>
        /// <param name="Points"></param>
        /// <returns></returns>
        public static Point[] IntToPoints(params int[] Points)
        {
            Point[] OutPts = new Point[Points.Length / 2];
            for (int a = 0; a < Points.Length; a += 2)
                OutPts[a / 2] = new Point(Points[a], Points[a + 1]);
            return OutPts;
        }

        /// <summary>
        /// Draw the header bar for our one
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="OneLine"></param>
        /// <param name="Model"></param>
        public static void DrawHeader(Graphics g, Rectangle Bounds, MM_Database_OneLine OneLine, MM_Database_Model Model, MM_Database_Assignment LastAssignment)
        {
            String LongName;
            String Name;

            if (OneLine.Document.DocumentElement.HasAttribute("BaseElement.LongName"))
            {
                Name = MM_Type_Converter.TitleCase(OneLine.Document.DocumentElement.Attributes["BaseElement.Name"].Value);
                LongName = MM_Type_Converter.TitleCase(OneLine.Document.DocumentElement.Attributes["BaseElement.LongName"].Value);
            }
            else
                LongName = Name = MM_Type_Converter.TitleCase(OneLine.Document.DocumentElement.Attributes["BaseElement.DisplayName"].Value);

                        String ExportedOn = "Exported on: " + DateTime.Now.ToShortDateString() + (LastAssignment == null ? "" : " (on " + LastAssignment.CompletedOn.ToShortDateString() + " by " + LastAssignment.CompletedBy.FullName.Substring(0,1) + LastAssignment.CompletedBy.FullName.Split(' ')[1].Substring(0,1)+")");

            String CIMFile = "CIM file: " + Model.Name;
            String OutText = (String.IsNullOrEmpty(LongName) || LongName.Equals(Name, StringComparison.CurrentCultureIgnoreCase)) ? Name : LongName + " (" + Name + ")";
            String County = "Unknown";
            if (OneLine.Document.DocumentElement.HasAttribute("BaseElement.County"))
                County = OneLine.Document.DocumentElement.Attributes["BaseElement.County"].Value;
            PointF LatLng = PointF.Empty;
            if (OneLine.Document.DocumentElement.HasAttribute("BaseElement.LatLong"))
                LatLng = MM_Serializable<PointF>.ConvertObject(OneLine.Document.DocumentElement.Attributes["BaseElement.LatLong"].Value, null);
            String Coord = String.Format("County: {0}\nLat={1:0.000}, Lng={2:0.000}", County, LatLng.Y, LatLng.X);


            //Now, write out our header
            g.FillRectangle(Brushes.SteelBlue, Bounds);
            using (Font Arial = new Font("Arial", 9))
            {
                int XCoord = Bounds.Right - (int)Math.Ceiling(g.MeasureString(ExportedOn + "\n" + CIMFile, Arial).Width);
                g.DrawString(ExportedOn, Arial, Brushes.White, XCoord, Bounds.Top + 3);
                g.DrawString(CIMFile, Arial, Brushes.White, XCoord, Bounds.Top + 21);
                g.DrawString(Coord, Arial, Brushes.White, Bounds.Left + 2, Bounds.Top + 3);
            }
            using (Font Arial = new Font("Arial", 15))
            {
                Size HeadSize = g.MeasureString(OutText, Arial).ToSize();
                g.DrawString(OutText, Arial, Brushes.White, Bounds.Left + ((Bounds.Width - HeadSize.Width) / 2), Bounds.Top + ((Bounds.Height - HeadSize.Height) / 2));
            }
        }

        /// <summary>
        /// Draw a switch
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="State"></param>
        public static void DrawSwitch(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, CheckState State)
        {
            bool IsVertical = Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Up || Orientation == enumOrientations.Down;
            Point Center = CenterRect(Bounds);
            Size SlashSize = new Size(6, 6);

            //Now, build our drawing brush
            using (Pen DrawPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
            {
                if (State == CheckState.Indeterminate)
                {
                    DrawPen.DashStyle = DashStyle.Dot;
                    using (Font BoldFont = new Font("Arial", 14, FontStyle.Bold))
                    using (SolidBrush DrawBrush = new SolidBrush(DrawPen.Color))
                        g.DrawString("?", BoldFont, DrawBrush, Bounds, CenterFormat);
                }


                if (State == CheckState.Unchecked)
                {
                    g.DrawLine(DrawPen, Point.Subtract(Center, SlashSize), Point.Add(Center, SlashSize));
                    if (IsVertical)
                        g.DrawLine(DrawPen, Center.X, Bounds.Top, Center.X, Bounds.Bottom - 1);
                    else
                        g.DrawLine(DrawPen, Bounds.Left, Center.Y, Bounds.Right - 1, Center.Y);
                }
                else if (IsVertical)
                {
                    g.DrawLine(Pens.Black, Center.X, Center.Y - SlashSize.Height, Center.X, Center.Y + SlashSize.Height);
                    g.DrawLines(DrawPen, IntToPoints(Center.X, Bounds.Top, Center.X, Center.Y - SlashSize.Height, Center.X + SlashSize.Width, Center.Y + SlashSize.Height));
                    g.DrawLine(DrawPen, Center.X, Center.Y + SlashSize.Height, Center.X, Bounds.Bottom - 1);


                }
                else
                {
                    g.DrawLine(Pens.Black, Center.X - SlashSize.Width, Center.Y, Center.X + SlashSize.Width, Center.Y);
                    g.DrawLines(DrawPen, IntToPoints(Bounds.Left, Center.Y, Center.X - SlashSize.Width, Center.Y, Center.X + SlashSize.Width, Center.Y - SlashSize.Height));
                    g.DrawLine(DrawPen, Center.X + SlashSize.Width, Center.Y, Bounds.Right - 1, Center.Y);

                }
            }
        }

        /// <summary>
        /// Draw an arrow from the corner of one rectangle to a point in another
        /// </summary>
        /// <param name="g"></param>
        /// <param name="SourceBounds"></param>
        /// <param name="TargetBounds"></param>
        public static void DrawArrow(Graphics g, Rectangle SourceBounds, Rectangle TargetBounds)
        {
            using (Pen LinePen = new Pen(Color.White, ThicknessOverride))
            using (GraphicsPath gp = new GraphicsPath(new Point[] { Point.Empty, new Point(-4, -4), Point.Empty, new Point(4, -4) }, new byte[] { 0, 1, 1, 129 }))
            using (CustomLineCap c = new CustomLineCap(null, gp))
            {
                LinePen.CustomStartCap = c;
                Point SourcePt, TargetPt;
                BuildArrowPath(SourceBounds, TargetBounds, out SourcePt, out TargetPt);
                g.DrawLine(LinePen, SourcePt, TargetPt);
            }
        }

        /// <summary>
        /// Determine the path from element to arrow target
        /// </summary>
        /// <param name="SourceBounds"></param>
        /// <param name="TargetBounds"></param>
        /// <param name="SourcePt"></param>
        /// <param name="TargetPt"></param>
        public static void BuildArrowPath(Rectangle SourceBounds, Rectangle TargetBounds, out Point SourcePt, out Point TargetPt)
        {
            SourcePt = Point.Empty;
            TargetPt = Point.Empty;
            if (SourceBounds.Right < TargetBounds.Left)
            {
                SourcePt.X = SourceBounds.Right;
                TargetPt.X = TargetBounds.Left;
            }
            else if (SourceBounds.Left > TargetBounds.Right)
            {
                SourcePt.X = SourceBounds.Left;
                TargetPt.X = TargetBounds.Right;
            }
            else
            {
                SourcePt.X = SourceBounds.Left + (SourceBounds.Width / 2);
                TargetPt.X = TargetBounds.Left + (TargetBounds.Width / 2);
            }

            if (SourceBounds.Bottom < TargetBounds.Top)
            {
                SourcePt.Y = SourceBounds.Bottom;
                TargetPt.Y = TargetBounds.Top;
            }
            else if (SourceBounds.Top > TargetBounds.Bottom)
            {
                SourcePt.Y = SourceBounds.Top;
                TargetPt.Y = TargetBounds.Bottom;
            }
            else
            {
                SourcePt.Y = SourceBounds.Top + (SourceBounds.Height / 2);
                TargetPt.Y = TargetBounds.Top + (TargetBounds.Height / 2);
            }
        }

        /// <summary>
        /// Build a dictionary with all RTNET and SCADA points in place
        /// </summary>
        /// <param name="xElem">Our XML defintion for the element with which the descriptor is associated</param>
        /// <param name="OneLineValues"></param>
        /// <param name="ElementBounds"></param>
        /// <param name="LabelBounds"></param>
        /// <returns></returns>
        public static MM_OneLine_Value[] BuildExportPointsWithLocations(XmlElement xElem, MM_OneLine_Value[] OneLineValues, Rectangle ElementBounds, Rectangle LabelBounds)
        {
            //Determine our vertical alignment of our label relative to the element
            List<MM_OneLine_Value> OutValues = new List<MM_OneLine_Value>();
            VerticalAlignment vAlign;
            if (LabelBounds.Bottom <= ElementBounds.Top)
                vAlign = VerticalAlignment.Top;
            else if (LabelBounds.Top >= ElementBounds.Bottom)
                vAlign = VerticalAlignment.Bottom;
            else
                vAlign = VerticalAlignment.Center;

            //Do the same for horizontal
            HorizontalAlignment hAlign;
            if (LabelBounds.Right <= ElementBounds.Left)
                hAlign = HorizontalAlignment.Left;
            else if (LabelBounds.Left >= ElementBounds.Right)
                hAlign = HorizontalAlignment.Right;
            else
                hAlign = HorizontalAlignment.Center;

            //Run through and set our estimated bounds
            if (OneLineValues[0].AssociatedElement.TypeName == "cim:SeriesCompensator")
            {

                /*foreach (MM_OneLine_Value Val in OneLineValues)
                    if (vAlign == VerticalAlignment.Top)
                        Val.Orientation = enumOrientations.Left;
                    else if (vAlign == VerticalAlignment.Bottom)
                        Val.Orientation = enumOrientations.Left;
                    else if (hAlign == HorizontalAlignment.Left)
                        Val.Orientation = enumOrientations.Up;
                    else if (hAlign == HorizontalAlignment.Right)                        
                        Val.Orientation = enumOrientations.Up;*/
                /*foreach (MM_OneLine_Value Val in OneLineValues)
                    if (Val.OutputMode == MM_OneLine_Value.enumOutputMode.Netmom && Val.ValueType == MM_OneLine_Value.enumValueType.AnalogLevel)
                        Console.WriteLine("{0}\t{1}\t{2}\t{3}", OneLineValues[0].AssociatedElement.LineName, Val.FlipDirection, Val.Orientation, xElem.Attributes["Orientation"].Value);
                  */
            }
            else if (OneLineValues[0].AssociatedElement.TypeName != "cim:ACLineSegment")
            {
                foreach (MM_OneLine_Value Val in OneLineValues)
                    if (vAlign == VerticalAlignment.Top)
                        Val.Orientation = enumOrientations.Up;
                    else if (vAlign == VerticalAlignment.Bottom)
                        Val.Orientation = enumOrientations.Down;
                    else if (hAlign == HorizontalAlignment.Left)
                        Val.Orientation = enumOrientations.Left;
                    else if (hAlign == HorizontalAlignment.Right)
                        Val.Orientation = enumOrientations.Right;
            }




            //If we're a transformer, handle things differently.
            if (xElem.Name == "Transformer")
            {
                XmlElement xXF = xElem.Name == "Transformer" ? xElem : xElem.ParentNode as XmlElement;
                enumOrientations[] Orientations = new enumOrientations[2];
                CIM_Element[] Windings = new CIM_Element[2];
                XmlElement[] xWindings = new XmlElement[2];
                foreach (MM_OneLine_Value Val in OneLineValues)
                    if (Val.OutputMode == MM_OneLine_Value.enumOutputMode.Netmom && Val.ValueType == MM_OneLine_Value.enumValueType.AnalogLevel)
                        foreach (XmlElement Winding in xXF.SelectNodes("Winding"))
                            if ((Winding.HasAttribute("rdfID") && Val.ValueSource.rdfID.ToString().Equals(Winding.Attributes["rdfID"].Value)) || (Winding.HasAttribute("BaseElement.TEID") && Val.ValueSource.TEID.Equals(Winding.Attributes["BaseElement.TEID"].Value)))
                            {
                                enumOrientations Orientation = MM_Serializable<enumOrientations>.ConvertObject(Winding.Attributes["Orientation"].Value, null);
                                Rectangle WindingBounds = MM_Serializable<Rectangle>.ConvertObject(Winding.Attributes["Bounds"].Value, null);
                                int Index = (Orientation == enumOrientations.Right || Orientation == enumOrientations.Up) ? 0 : 1;
                                //int Index = WindingBounds.Location.IsEmpty ? 0 : 1;
                                Windings[Index] = Val.ValueSource;
                                xWindings[Index] = Winding;
                                Orientations[Index] = Orientation;
                                Val.Orientation = Orientation;
                            }

                foreach (MM_OneLine_Value.enumOutputMode Mode in Enum.GetValues(typeof(MM_OneLine_Value.enumOutputMode)))
                {
                    MM_OneLine_Value Label = null;
                    List<MM_OneLine_Value>[] OutVals = new List<MM_OneLine_Value>[] { new List<MM_OneLine_Value>(5), new List<MM_OneLine_Value>(5) };
                    foreach (MM_OneLine_Value Value in OneLineValues)
                        if (Value.OutputMode == Mode)
                        {
                            if (Value.ValueType == MM_OneLine_Value.enumValueType.Label)
                                Label = Value;
                            else if (Value.ValueSource == Windings[0] || Value.AssociatedElement == Windings[0])
                            {
                                OutVals[0].Add(Value);
                                Value.xElem = xWindings[0];
                            }
                            else if (Value.ValueSource == Windings[1] || Value.AssociatedElement == Windings[1])
                            {
                                OutVals[1].Add(Value);
                                Value.xElem = xWindings[1];
                            }
                            Value.Bounds = new Rectangle(Point.Empty, Value.EstimatedSize);
                        }


                    //First, determine the position of our label
                    if (hAlign == HorizontalAlignment.Left)
                        Label.Left = LabelBounds.Right - Label.Bounds.Width;
                    else if (hAlign == HorizontalAlignment.Right)
                        Label.Left = LabelBounds.Left;
                    else
                        Label.Left = (LabelBounds.Left + (LabelBounds.Width / 2) - (Label.Bounds.Width / 2));

                    if (vAlign == VerticalAlignment.Top)
                        Label.Top = LabelBounds.Bottom - Label.Height;
                    else if (vAlign == VerticalAlignment.Bottom)
                        Label.Top = LabelBounds.Top;
                    else if (vAlign == VerticalAlignment.Center)
                        Label.Top = LabelBounds.Top + (LabelBounds.Height / 2) - (Label.Height / 2);
                    OutValues.Add(Label);

                    //Now, continue to put elements in place, depending on the orientation of the windings.
                    Rectangle CurrentBounds = Label.Bounds;
                    Point CenterRect = MM_OneLine_Element.CenterRect(CurrentBounds);
                    if (Orientations[0] == enumOrientations.Up || Orientations[0] == enumOrientations.Down || Orientations[1] == enumOrientations.Up || Orientations[1] == enumOrientations.Down)
                    {
                        for (int a = 0; a < 2; a++)
                            if (OutVals[a].Count > 0)
                            {
                                CurrentBounds = Label.Bounds;
                                int Min = a == 0 ? OutVals[a].Count - 1 : 0;
                                int Max = a == 0 ? -1 : OutVals[a].Count;
                                int Incr = a == 0 ? -1 : 1;
                                for (int b = Min; b != Max; b += Incr)
                                {
                                    MM_OneLine_Value Val = OutVals[a][b];
                                    Val.Size = Val.EstimatedSize;

                                    //Set our X coordinate
                                    if (hAlign == HorizontalAlignment.Left)
                                        Val.Left = Label.Right - Val.Width;
                                    else if (hAlign == HorizontalAlignment.Right)
                                        Val.Left = Label.Left;
                                    else
                                        Val.Left = CenterRect.X - (Val.Width / 2);

                                    //Determine our Y coordinate
                                    if (a == 0)
                                    {
                                        Val.Top = CurrentBounds.Top - Val.Height;
                                        CurrentBounds.Y -= Val.Height;
                                        CurrentBounds.Height += Val.Height;
                                    }
                                    else
                                    {
                                        Val.Top = CurrentBounds.Bottom;
                                        CurrentBounds.Height += Val.Height;
                                    }
                                    OutValues.Add(Val);
                                }
                            }
                    }
                    else
                        for (int a = 0; a < 2; a++)
                            if (OutVals[a].Count > 0)
                            {
                                CurrentBounds = Label.Bounds;
                                int Min = vAlign == VerticalAlignment.Top ? OutVals[a].Count - 1 : 0;
                                int Max = vAlign == VerticalAlignment.Top ? -1 : OutVals[a].Count;
                                int Incr = vAlign == VerticalAlignment.Top ? -1 : 1;
                                for (int b = Min; b != Max; b += Incr)


                                //foreach (MM_OneLine_Value Val in OutVals[a])
                                {
                                    MM_OneLine_Value Val = OutVals[a][b];
                                    Val.Size = Val.EstimatedSize;
                                    if (a == 0)
                                        Val.Left = CenterRect.X - Val.Width;
                                    else
                                        Val.Left = CenterRect.X;

                                    if (vAlign == VerticalAlignment.Top)
                                    {
                                        Val.Top = CurrentBounds.Top - Val.Height;
                                        CurrentBounds.Y -= Val.Height;
                                        CurrentBounds.Height += Val.Height;
                                    }
                                    else
                                    {
                                        Val.Top = CurrentBounds.Bottom;
                                        CurrentBounds.Height += Val.Height;
                                    }
                                    OutValues.Add(Val);
                                }
                            }
                }

            }
            else
            {
                //Start putting our labels in 
                int[] LeftMost = new int[] { int.MaxValue, int.MaxValue }, BottomMost = new int[] { int.MaxValue, int.MaxValue };
                foreach (MM_OneLine_Value Value in OneLineValues)
                    foreach (MM_OneLine_Value.enumOutputMode Mode in Enum.GetValues(typeof(MM_OneLine_Value.enumOutputMode)))
                        if (Value.OutputMode == Mode)
                            if (Value.ValueType == MM_OneLine_Value.enumValueType.FrequencyPanel)
                            {
                                //First, find our NETMOM analog label.
                                MM_OneLine_Value NetmomLbl = null;
                                foreach (MM_OneLine_Value Val in OutValues)
                                    if (Val.ValueType == MM_OneLine_Value.enumValueType.AnalogLevel && Val.OutputMode == MM_OneLine_Value.enumOutputMode.Netmom)
                                        NetmomLbl = Val;
                                Value.Bounds = new Rectangle(Point.Empty, Value.EstimatedSize);
                                if (hAlign == HorizontalAlignment.Left)
                                    Value.Location = new Point(NetmomLbl.Left, NetmomLbl.Bottom);
                                else if (hAlign == HorizontalAlignment.Right || vAlign == VerticalAlignment.Top)
                                    Value.Location = new Point(NetmomLbl.Right, NetmomLbl.Top);
                                else if (vAlign == VerticalAlignment.Bottom)
                                    Value.Location = new Point(NetmomLbl.Left, NetmomLbl.Bottom);
                                OutValues.Add(Value);
                            }
                            else
                            {
                                Value.Bounds = new Rectangle(Point.Empty, Value.EstimatedSize);

                                //First, build out the size and X coordinate of our rectangle
                                if (hAlign == HorizontalAlignment.Left)
                                {
                                    int NewLeft = LabelBounds.Right - Value.Width;
                                    if (NewLeft < LeftMost[(int)Mode])
                                    {
                                        LeftMost[(int)Mode] = NewLeft;
                                        foreach (MM_OneLine_Value ValueToShift in OutValues)
                                            if (ValueToShift.OutputMode == Mode)
                                                ValueToShift.Left = NewLeft;
                                    }
                                    Value.Left = LeftMost[(int)Mode];
                                }
                                else if (hAlign == HorizontalAlignment.Right)
                                    Value.Left = LabelBounds.Left;
                                else
                                    Value.Left = (LabelBounds.Left + (LabelBounds.Width / 2) - (Value.Bounds.Width / 2));

                                //Now, do the same for the vertical
                                if (vAlign == VerticalAlignment.Top)
                                {
                                    //Move all elements up by our target size height
                                    foreach (MM_OneLine_Value ShiftValue in OutValues)
                                        if (ShiftValue.OutputMode == Mode)
                                            ShiftValue.Top -= Value.Bounds.Height;
                                    Value.Top = LabelBounds.Bottom - Value.Bounds.Height;
                                }
                                else if (vAlign == VerticalAlignment.Bottom)
                                {
                                    if (BottomMost[(int)Mode] == int.MaxValue)
                                        BottomMost[(int)Mode] = LabelBounds.Top;
                                    Value.Top = BottomMost[(int)Mode];
                                    BottomMost[(int)Mode] = Value.Bounds.Bottom;
                                }
                                else if (vAlign == VerticalAlignment.Center)
                                {
                                    //Move all elements by half our target size height
                                    foreach (MM_OneLine_Value ShiftValue in OutValues)
                                        if (ShiftValue.OutputMode == Mode)
                                            ShiftValue.Top -= (Value.Bounds.Height / 2);
                                    if (BottomMost[(int)Mode] == int.MaxValue)
                                        BottomMost[(int)Mode] = LabelBounds.Top + (LabelBounds.Height / 2);

                                    Value.Top = BottomMost[(int)Mode] - (Value.Bounds.Height / 2);
                                    BottomMost[(int)Mode] = Value.Bounds.Bottom;
                                }
                                OutValues.Add(Value);
                            }
            }
            return OutValues.ToArray();
        }




        /// <summary>
        /// Build the set of export points around our element
        /// </summary>
        /// <param name="Elem">The element to build points around</param>
        /// <param name="BaseElement">Our base element, such as substation or substation</param>
        /// <param name="SecondaryDescriptor">Whether this element is a secondary descriptor</param>
        /// <param name="xElem">The XML element corresponding to this new one</param>
        /// <returns></returns>                
        public static MM_OneLine_Value[] BuildExportPoints(CIM_Element Elem, CIM_Element BaseElement, bool SecondaryDescriptor, XmlElement xElem)
        {
            List<MM_OneLine_Value> OutValues = new List<MM_OneLine_Value>();
            //When we have transformers, go by windings[0] -> label -> windings[1]
            if (Elem.TypeName == "etx:PricingVector")
            {
                OutValues.Add(new MM_OneLine_Value(Elem.ParseSingle("etx:EPSMeter", null), Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                OutValues.Add(new MM_OneLine_Value(Elem.ParseSingle("etx:EPSMeter", null), Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
            }
            else if (SecondaryDescriptor)
            {
                OutValues.Add(new MM_OneLine_Value(Elem.ParseSingle("etx:ElectricalBus<etx:ResourceNode", null), Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                OutValues.Add(new MM_OneLine_Value(Elem.ParseSingle("etx:ElectricalBus<etx:ResourceNode", null), Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
            }
            else if (Elem.TypeName == "cim:PowerTransformer")
            {
                CIM_Element[] Windings = Elem.Parse("cim:TransformerWinding", null);
                if (Windings.Length == 2)
                {
                    OutValues.AddRange(FindAnalogs(Windings[0], Windings[0].ParseSingle("cim:Terminal", null), BaseElement, xElem));
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                    OutValues.AddRange(FindAnalogs(Windings[1], Windings[1].ParseSingle("cim:Terminal", null), BaseElement, xElem));

                    //Do the same for the Netmom

                    //TODO: Add the following code if NETMOM XFWs should only show on primary: && Windings[0]["cim:TransformerWinding.windingType"].EndsWith(".primary"))


                    if (Windings[0].VoltageLevel.Name != "1 KV")
                        OutValues.Add(new MM_OneLine_Value(Windings[0], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                    if (Windings[1].VoltageLevel.Name != "1 KV")
                        OutValues.Add(new MM_OneLine_Value(Windings[1], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                }
                else
                    throw new InvalidOperationException("Can't determine what windings to write analogs on: " + Elem.Name + " / " + Elem.rdfID.ToString());
            }
            else if (Elem.TypeName == "cim:ACLineSegment")
                if (BaseElement.TypeName == "cim:Substation" && Elem.TypeName == "cim:ACLineSegment")
                {
                    //First, find our target substation
                    foreach (CIM_Element Sub in Elem.ACSegmentStations)
                        if (!Sub.Equals(BaseElement))
                        {
                            OutValues.Add(new MM_OneLine_Value(Sub, Elem, MM_OneLine_Value.enumValueType.LabelWithNavigation, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                            OutValues.Add(new MM_OneLine_Value(Sub, Elem, MM_OneLine_Value.enumValueType.LabelWithNavigation, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                        }

                    //Find our node on this side of the substation
                    foreach (CIM_Element Node in Elem.Nodes)
                        if (Node.Substation.Equals(BaseElement))
                            OutValues.Add(new MM_OneLine_Value(Node, Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));

                    foreach (CIM_Element LineTerminal in Elem.Parse("cim:Terminal", null))
                        if (LineTerminal.Substation.Equals(BaseElement))
                            OutValues.AddRange(FindAnalogs(Elem, LineTerminal, BaseElement, xElem));
                }
                else
                {
                    CIM_Element[] Terminals = Elem.Parse("cim:Terminal", null);
                    if (Terminals.Length == 2)
                    {
                        foreach (MM_OneLine_Value Val in FindAnalogs(Elem, Terminals[0], BaseElement, xElem))
                        {
                            Val.Orientation = xElem.ParentNode.Attributes["Orientation"] != null && xElem.ParentNode.Attributes["Orientation"].Value == "Vertical" ? enumOrientations.Down : enumOrientations.Right;
                            OutValues.Add(Val);
                        }
                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                        foreach (MM_OneLine_Value Val in FindAnalogs(Elem, Terminals[1], BaseElement, xElem))
                        {
                            Val.Orientation = xElem.ParentNode.Attributes["Orientation"] != null && xElem.ParentNode.Attributes["Orientation"].Value == "Vertical" ? enumOrientations.Up : enumOrientations.Left;
                            OutValues.Add(Val);
                        }

                        MM_OneLine_Value NewVal = new MM_OneLine_Value(Elem.Nodes[0], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false);
                        NewVal.Orientation = xElem.ParentNode.Attributes["Orientation"] != null && xElem.ParentNode.Attributes["Orientation"].Value == "Vertical" ? enumOrientations.Down : enumOrientations.Right;
                        OutValues.Add(NewVal);

                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));

                        NewVal = new MM_OneLine_Value(Elem.Nodes[1], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false);
                        NewVal.Orientation = xElem.ParentNode.Attributes["Orientation"] != null && xElem.ParentNode.Attributes["Orientation"].Value == "Vertical" ? enumOrientations.Up : enumOrientations.Left;
                        OutValues.Add(NewVal);
                    }
                    else
                        throw new InvalidOperationException("Can't determine what terminals to write line analogs on: " + Elem.Name + " / " + Elem.rdfID.ToString());
                }
            else if (Elem.TypeName == "cim:SeriesCompensator")
            {
                CIM_Element NearNode = null;
                foreach (CIM_Link Terminal in Elem.Links)
                    if (Terminal.TypeName == "cim:Terminal" && bool.Parse(Terminal.Element["etx:Terminal.near"]))
                        NearNode = Terminal.Element.ParseSingle("cim:ConnectivityNode", null);
                CIM_Element[] Terminals = Elem.Parse("cim:Terminal", null);
                if (Terminals.Length == 2)
                {
                    //Determine the telemetry on both sides for SCADA, and add in the direction we want.
                    MM_OneLine_Value[] NearSide = FindAnalogs(Elem, Terminals[0], BaseElement, xElem).ToArray();
                    MM_OneLine_Value[] FarSide = FindAnalogs(Elem, Terminals[1], BaseElement, xElem).ToArray();


                    if (FarSide.Length == 0)
                    {
                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                        OutValues.AddRange(NearSide);
                    }
                    else
                    {
                        OutValues.AddRange(NearSide);
                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                        OutValues.AddRange(FarSide);
                    }

                    //Add in our netmom analogs     

                    //Find our node references to our series compensator, in order to determine direction.
                    Rectangle NearNodeRect = Rectangle.Empty;
                    Rectangle ElemRect = MM_Serializable<Rectangle>.ConvertObject(xElem.Attributes["Bounds"].Value, null);
                    foreach (String str in ("rdfID='" + Elem.rdfID.ToString() + "'," + "TEID='" + Elem.TEID + "'").Split(','))
                        foreach (XmlNode NodeToAdd in xElem.OwnerDocument.SelectNodes("/One_Line/Nodes/Node/*" + "[@" + str + "]"))
                            if (NodeToAdd.ParentNode.Attributes["rdfID"].Value == NearNode.rdfID.ToString())
                                if (NodeToAdd.ChildNodes.Count == 0)
                                    NearNodeRect = MM_Serializable<Rectangle>.ConvertObject(NodeToAdd.ParentNode.Attributes["Bounds"].Value, null);
                                else if (NodeToAdd.ChildNodes.Count == 1)
                                    NearNodeRect = MM_Serializable<Rectangle>.ConvertObject(NodeToAdd.ChildNodes[0].Attributes["Bounds"].Value, null);
                                else
                                { }

                    enumOrientations NodeOrientation = MM_OneLine_Validation.DetermineOrientation(ElemRect, NearNodeRect);

                    if (Elem.Nodes[0].Equals(NearNode))
                    {
                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                        OutValues.Add(new MM_OneLine_Value(Elem.Nodes[0], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, true, NodeOrientation));
                    }
                    else
                    {
                        OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                        OutValues.Add(new MM_OneLine_Value(Elem.Nodes[1], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, true, NodeOrientation));
                    }




                    /* OutValues.Add(new MM_OneLine_Value(Elem.Nodes[0], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, Elem.Nodes[0].Equals(NearNode), NodeOrientation));
                     OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                     OutValues.Add(new MM_OneLine_Value(Elem.Nodes[1], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, Elem.Nodes[1].Equals(NearNode), NodeOrientation));
                     if (Elem.Nodes[0].Equals(NearNode))
                     {                     
                         OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                         OutValues.Add(new MM_OneLine_Value(Elem.Nodes[0], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem,true));
                     }
                     else
                     {                     
                         OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                         OutValues.Add(new MM_OneLine_Value(Elem.Nodes[1], Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem,false));
                     }*/
                }
            }
            else if (Elem.TypeName == "cim:Breaker" || Elem.TypeName == "cim:Disconnector" || Elem.TypeName == "cim:GroundDisconnector")
            {

                //If our base is a breaker-to-breaker, find all traces that hold our element
                if (BaseElement is CIM_Trace && !BaseElement.Name.StartsWith("D"))
                {
                    //UInt64 ElemTEID = Convert.ToUInt64(Elem.TEID);
                    foreach (CIM_Trace Trace in BaseElement.CIM.Traces.Values)
                        if (Trace != BaseElement && !Trace.Name.StartsWith("D") && Array.IndexOf(Trace.rdfIDs, Elem.rdfID) != -1)
                        {
                            OutValues.Add(new MM_OneLine_Value(Trace, MM_OneLine_Value.enumValueType.LabelWithNavigation, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                            //OutValues.Add(new MM_OneLine_Value(Elem.Substation, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                            OutValues.Add(new MM_OneLine_Value(Trace, MM_OneLine_Value.enumValueType.LabelWithNavigation, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                            //OutValues.Add(new MM_OneLine_Value(Elem.Substation, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                        }
                }


                CIM_Element Discrete = null;
                foreach (CIM_Element DiscToTest in Elem.Parse("Discrete<DiscreteValue", null))
                    if (DiscToTest.Name == "ST")
                        Discrete = DiscToTest;
                if (Discrete == null)
                {
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                }
                else
                {
                    CIM_Element Meas = Discrete.ParseSingle("MeasurementGroup", null);
                    if (Meas == null)
                        Meas = Discrete.ParseSingle("Calculation", null);
                    OutValues.Add(new MM_OneLine_Value(Meas, Elem, MM_OneLine_Value.enumValueType.BreakerSwitchLabel, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                    OutValues.Add(new MM_OneLine_Value(Meas, Elem, MM_OneLine_Value.enumValueType.BreakerSwitchLabel, MM_OneLine_Value.enumOutputMode.Netmom, xElem, false));
                }

                //Also, check for analogs                
                List<CIM_Element> WrittenAnalogs = new List<CIM_Element>();
                foreach (CIM_Element Term in Elem.Parse("cim:Terminal", null))
                    foreach (MM_OneLine_Value OutAnalog in FindAnalogs(Elem, Term, BaseElement, xElem))
                        if (!WrittenAnalogs.Contains(OutAnalog.ValueSource))
                        {
                            OutValues.Add(OutAnalog);
                            WrittenAnalogs.Add(OutAnalog.ValueSource);
                        }                               
            }
            else
            {
                OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Scada, xElem));
                List<CIM_Element> WrittenAnalogs = new List<CIM_Element>();
                foreach (CIM_Element Term in Elem.Parse("cim:Terminal", null))
                    foreach (MM_OneLine_Value OutAnalog in FindAnalogs(Elem, Term, BaseElement, xElem))
                        if (!WrittenAnalogs.Contains(OutAnalog.ValueSource))
                        {
                            OutValues.Add(OutAnalog);
                            WrittenAnalogs.Add(OutAnalog.ValueSource);
                        }
                OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.Label, MM_OneLine_Value.enumOutputMode.Netmom, xElem));

                if (Elem.TypeName == "cim:ConnectivityNode")
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.KVLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                else if (Elem.TypeName != "etx:EndCap")
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Netmom, xElem));
                if (Elem.TypeName == "cim:SynchronousMachine")
                    OutValues.Add(new MM_OneLine_Value(Elem, MM_OneLine_Value.enumValueType.FrequencyPanel, MM_OneLine_Value.enumOutputMode.Netmom, xElem));

            }
            return OutValues.ToArray();
        }




        /// <summary>
        /// Build a collection of all found analogs
        /// </summary>
        /// <param name="Elem">The element to search around</param>
        /// <param name="BaseElement">Our base element, such as substation</param>
        /// <param name="Term">Our terminal to search around</param>
        /// <param name="xElem">Our XML element</param>
        /// <returns></returns>
        public static List<MM_OneLine_Value> FindAnalogs(CIM_Element Elem, CIM_Element Term, CIM_Element BaseElement, XmlElement xElem)
        {

            string[] AnalogsToSearchFor = Elem.CIM.PUNElements.ContainsKey(Elem.rdfID) ? PUNAnalogs : Elem.ElemType=="Unit" ? UnitAnalogs:Analogs;

            if (Term.TypeName != "cim:Terminal")
                throw new InvalidOperationException("Can only locate analogs against terminals!");

            //If our terminal isn't pointing to our element (or busbar section if node), return.            
            CIM_Element TargetElem = Elem.CIM.FromRdfID(new CIM_RdfID(Term["cim:Terminal.ConductingEquipment"].Substring(1)));

            List<MM_OneLine_Value> OutValues = new List<MM_OneLine_Value>();
            if (!TargetElem.Equals(Elem) && !(TargetElem.TypeName == "cim:BusbarSection" && Elem.TypeName == "cim:ConnectivityNode"))
                return OutValues;

            //JLH
            if (Elem.Name == "7565")
            {
                Console.WriteLine("Let's check here");
            }

            //First, search through our analogs
            Dictionary<String, CIM_Element> MeasurementsToCheck = new Dictionary<string, CIM_Element>();
            foreach (CIM_Element Analog in Term.Parse("cim:Analog", null))
            {
                bool ForNetwork = XmlConvert.ToBoolean(Analog["etx:Analog.forNetwork"]);
                bool HasPseudoTerminal = Analog.ParseSingle("etx:PseudoTerminal", null) != null;
                if (!ForNetwork && !HasPseudoTerminal)
                    if (BaseElement.TypeName != "cim:Substation" || (Analog.ParseSingle("cim:Terminal", null).Substation.Equals(BaseElement)))
                        if (Analog.ParseSingle("AnalogValue>AnalogName", null) != null)
                            if (Array.IndexOf(AnalogsToSearchFor, Analog.ParseSingle("AnalogValue>AnalogName", null).Name) != -1)
                                MeasurementsToCheck.Add(Analog.ParseSingle("AnalogValue>AnalogName", null).Name, Analog);
            }
            foreach (CIM_Element Discrete in Term.Parse("cim:Discrete", null))
            {
                bool HasPseudoTerminal = Discrete.ParseSingle("etx:PseudoTerminal", null) != null;
                if (!HasPseudoTerminal)
                    if (BaseElement.TypeName != "cim:Substation" || (Discrete.ParseSingle("cim:Terminal", null).Substation.Equals(BaseElement)))
                        if (Array.IndexOf(AnalogsToSearchFor, Discrete.Name) != -1)
                            MeasurementsToCheck.Add(Discrete.Name, Discrete);
            }

          
            //Now, go through our list, and produce them one by one      
            CIM_Element FoundAnalog;
            foreach (String AnalogToFind in AnalogsToSearchFor)
                if (MeasurementsToCheck.TryGetValue(AnalogToFind, out FoundAnalog))
                    if (AnalogToFind == "MW" || AnalogToFind == "MVAR" || AnalogToFind == "MVA" || AnalogToFind == "GMW" || AnalogToFind == "GMV")
                        OutValues.Add(new MM_OneLine_Value(FoundAnalog, Elem, MM_OneLine_Value.enumValueType.AnalogLevel, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                    else if (AnalogToFind == "KV")
                        OutValues.Add(new MM_OneLine_Value(FoundAnalog, Elem, MM_OneLine_Value.enumValueType.KVLevel, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                    else if (AnalogToFind == "AVR")
                        OutValues.Add(new MM_OneLine_Value(FoundAnalog, Elem, MM_OneLine_Value.enumValueType.AVRValue, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                    else if (AnalogToFind == "PSS")
                        OutValues.Add(new MM_OneLine_Value(FoundAnalog, Elem, MM_OneLine_Value.enumValueType.PSSValue, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
                    else if (AnalogToFind == "TAP")
                        OutValues.Add(new MM_OneLine_Value(FoundAnalog, Elem, MM_OneLine_Value.enumValueType.TapValue, MM_OneLine_Value.enumOutputMode.Scada, xElem, false));
            return OutValues;


        }


        /// <summary>
        /// Draw a descriptor for an element
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Elem"></param>
        /// <param name="BaseElement"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="xDesc"></param>
        /// <param name="Model"></param>
        public static void DrawDescriptor(Graphics g, CIM_Element Elem, CIM_Element BaseElement, XmlElement xDesc, Rectangle Bounds, Brush BackBrush, MM_Database_Model Model)
        {
            bool SecondaryDescriptor = xDesc.Name == "SecondaryDescriptor";
            FontStyle DrawStyle = SecondaryDescriptor ? FontStyle.Italic : FontStyle.Regular;
            
            
            if (Elem.TypeName == "cim:Breaker")
            {
                MM_Database_Connector Db = Elem.CIM.Repository.Db;
                bool HasSynchrocheck = Db.Synchrocheck_Relays.ContainsKey(Elem.rdfID) || Db.Synchrocheck_Relays.ContainsKey(Elem.Substation.rdfID) || Db.Synchrocheck_Relays.ContainsKey(Elem.Operator == null ? Elem.Substation.Operator.rdfID : Elem.Operator.rdfID);
                bool HasSynchroscope = Db.Synchroscopes.ContainsKey(Elem.rdfID) || Db.Synchroscopes.ContainsKey(Elem.Substation.rdfID) || Db.Synchroscopes.ContainsKey(Elem.Operator == null ? Elem.Substation.Operator.rdfID : Elem.Operator.rdfID);                                    
                if (HasSynchrocheck)
                    DrawStyle |= FontStyle.Italic;
                if (HasSynchroscope)
                    DrawStyle |= FontStyle.Bold;
            }             
            using (Font Arial = new Font("Arial", 8,DrawStyle))
                g.DrawString(DescriptorText(Elem, BaseElement, SecondaryDescriptor), Arial, WhiteBackground ? Brushes.Black : Brushes.LightGray, Bounds, MM_OneLine_Element.CenterFormat);
        }

        /// <summary>
        /// Report the descriptor text for a particular element
        /// </summary>
        /// <param name="Elem"></param>
        /// <param name="BaseElement"></param>
        /// <param name="Secondary"></param>
        /// <returns></returns>
        public static String DescriptorText(CIM_Element Elem, CIM_Element BaseElement, bool Secondary)
        {
            String SubAdd = BaseElement is CIM_Trace && Elem.Substation != null ? MM_Type_Converter.TitleCase(Elem.Substation.Name) + "." : "";
            if (Elem == null)
                return SubAdd + "???";
            else if (Elem.TypeName == "cim:ACLineSegment" || Elem.TypeName == "cim:SeriesCompensator")
            {
                CIM_Element ParentLine = Elem.ParseSingle("cim:Line", null);
                if (Elem.TypeName == "cim:SeriesCompensator")
                    return SubAdd + MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : Elem.Name));
                else if (BaseElement == null || BaseElement.TypeName != "cim:Substation")
                    if (Elem.ACSegmentStations[0].Equals(Elem.ACSegmentStations[1]))
                        return SubAdd + MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : Elem.Name));
                    else
                        return SubAdd + MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : Elem.Name) + "\n(" + Elem.ACSegmentStations[0].LongName + " to " + Elem.ACSegmentStations[1].LongName + ")");
                else
                    foreach (CIM_Element ACStn in Elem.ACSegmentStations)
                        if (!ACStn.Equals(BaseElement))
                            if (Secondary)
                                return SubAdd + MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : Elem.Name) + " ( to " + ACStn.LongName + ")");
                            else
                                return SubAdd + MM_Type_Converter.TitleCase(ACStn.LongName + "\n(" + ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : Elem.Name) + ")");
                return "?";
            }
            else if (Elem.TypeName == "etx:PricingVector")
            {
                CIM_Element EPS = Elem.ParseSingle("etx:EPSMeter", null);
                if (Secondary)
                    return SubAdd + MM_Type_Converter.TitleCase((Secondary ? Elem.Name + " - " : "") + EPS.Name + " - " + EPS["etx:EPSMeter.RID"]);
                else
                    return SubAdd + MM_Type_Converter.TitleCase(EPS.Name + "\n" + EPS["etx:EPSMeter.RID"]);
            }
            else if (Elem.TypeName == "cim:ConnectivityNode" && Elem.ParseSingle("etx:ElectricalBus<etx:ResourceNode", null) != null)
                if (Secondary)
                    return SubAdd + MM_Type_Converter.TitleCase(Elem.ParseSingle("etx:ElectricalBus<etx:ResourceNode", null).Name);
                else
                    return SubAdd + MM_Type_Converter.TitleCase(Elem.Name);
            else if (Elem.TypeName == "cim:PowerTransformer")
            {
                String WindingType;
                foreach (CIM_Element XFW in Elem.TransformerWinding)
                    if (XFW.Attributes.TryGetValue("cim:TransformerWinding.windingType", out WindingType) && WindingType.EndsWith(".primary"))
                        return SubAdd + MM_Type_Converter.TitleCase(XFW.Name);
                return SubAdd + MM_Type_Converter.TitleCase(Elem.Name);
            }
            else if (Elem.TypeName == "cim:SynchronousMachine")
            {
                return Elem.ParseSingle("Unit", null).Name;
            }
            else
                return SubAdd + MM_Type_Converter.TitleCase(Elem.Name);
        }


        /// <summary>
        /// Draw the breaker at the requested location
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="State"></param>
        public static void DrawBreaker(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, CheckState State)
        {
            Rectangle DrawRect = new Rectangle(Bounds.Left + 2, Bounds.Top + 2, Bounds.Width - 5, Bounds.Height - 5);
            Color DrawColor = KVLevel == null ? Color.Red : KVLevel.Energized.ForeColor;
            Point Center = CenterRect(Bounds);

            using (Font DrawFont = new Font("Arial", 13, FontStyle.Bold))
            using (SolidBrush ForeBrush = new SolidBrush(DrawColor))
            using (Pen DrawPen = new Pen(DrawColor, ThicknessOverride))
            {
                if (State == CheckState.Checked)
                {
                    g.FillRectangle(BackBrush, DrawRect);
                    g.DrawRectangle(DrawPen, DrawRect);
                    g.DrawString("O", DrawFont, ForeBrush, DrawRect, CenterFormat);
                }
                else if (State == CheckState.Unchecked)
                {
                    g.FillRectangle(ForeBrush, DrawRect);
                    g.DrawString("C", DrawFont, BackBrush, DrawRect, CenterFormat);
                }
                else if (State == CheckState.Indeterminate)
                {
                    g.FillRectangle(BackBrush, DrawRect);
                    using (HatchBrush hb = new HatchBrush(HatchStyle.Percent50, Color.FromArgb(64, KVLevel == null ? Color.Red : KVLevel.Energized.ForeColor), Color.Transparent))
                        g.FillRectangle(hb, DrawRect);
                    g.DrawRectangle(DrawPen, DrawRect);
                    g.DrawString("?", DrawFont, ForeBrush, DrawRect, CenterFormat);
                }

                if (Orientation == enumOrientations.Right || Orientation == enumOrientations.Horizontal)
                    g.DrawLine(DrawPen, Bounds.Left, Center.Y, DrawRect.Left, Center.Y);
                if (Orientation == enumOrientations.Left || Orientation == enumOrientations.Horizontal)
                    g.DrawLine(DrawPen, DrawRect.Right, Center.Y, Bounds.Right - 1, Center.Y);
                if (Orientation == enumOrientations.Down || Orientation == enumOrientations.Vertical)
                    g.DrawLine(DrawPen, Center.X, Bounds.Top, Center.X, DrawRect.Top);
                if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical)
                    g.DrawLine(DrawPen, Center.X, DrawRect.Bottom, Center.X, Bounds.Bottom - 1);
            }
        }

        /// <summary>
        /// Draw a capactior
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="BackBrush"></param>
        /// <param name="GroundBar"></param>
        public static void DrawCapacitor(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool GroundBar)
        {
            using (SolidBrush sB = new SolidBrush(Color.FromArgb(20, 20, 20)))
                g.FillRectangle(sB, Bounds);
            Point Center = CenterRect(Bounds);
            using (Pen DrawingPen = (KVLevel == null ? new Pen(Color.Red, ThicknessOverride) : new Pen(KVLevel.Energized.ForeColor, ThicknessOverride)))                
                if (Orientation == enumOrientations.Up)
                {
                    g.DrawLine(DrawingPen, Center.X, Bounds.Top, Center.X, Center.Y - 1);
                    g.DrawLine(DrawingPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Top);
                    g.DrawArc(DrawingPen, Bounds.Left, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 180, 180);
                }
                else if (Orientation == enumOrientations.Down)
                {
                    int Third = Bounds.Height/3;

                    g.DrawLine(KVLevel.Energized.ForePen, Center.X, Bounds.Top, Center.X, Bounds.Top + (Bounds.Height / 4));
                    g.DrawLine(DrawingPen, Bounds.Left+2, Bounds.Top + Third, Bounds.Right - 3, Bounds.Top + Third);
                    g.DrawArc(DrawingPen, Bounds.Left, Bounds.Top-Third-Third, Bounds.Width - 1, Bounds.Height -3, 0, 180);
                }
                else if (Orientation == enumOrientations.Left || Orientation == enumOrientations.Unknown)
                {
                    g.DrawLine(DrawingPen, Bounds.Left, Center.Y, Bounds.Right - 1, Center.Y);
                    g.DrawLine(DrawingPen, Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1);
                    g.DrawArc(DrawingPen, Bounds.Left + 1, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 90, 180);
                }
                else if (Orientation == enumOrientations.Right)
                {
                    g.DrawLine(DrawingPen, Bounds.Left, Center.Y, Bounds.Right - 1, Center.Y);
                    g.DrawLine(DrawingPen, Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                    g.DrawArc(DrawingPen, Bounds.Left - 1, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 270, 180);
                }
                else if (Orientation == enumOrientations.Horizontal)
                {
                    g.DrawLine(DrawingPen, Bounds.Left, Center.Y, Bounds.Right - 1, Center.Y);
                    g.DrawLine(DrawingPen, Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                    g.DrawArc(DrawingPen, Bounds.Left - 1, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 270, 180);
                }
                else if (Orientation == enumOrientations.Vertical)
                {
                    g.DrawLine(DrawingPen, Center.X, Bounds.Top, Center.X, Bounds.Bottom - 1);
                    g.DrawLine(DrawingPen, Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1);
                    g.DrawArc(DrawingPen, Bounds.Left, Bounds.Top - 1, Bounds.Width - 1, Bounds.Height - 1, 0, 180);
                }
            if (GroundBar)
                DrawGroundBar(g, Bounds, BackBrush, Orientation, KVLevel);
                
        }

        /// <summary>
        /// Draw an endcap
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawEndCap(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            using (Brush CircleBrush = new SolidBrush(KVLevel == null ? Color.Red : KVLevel.Energized.ForeColor))
                g.FillEllipse(CircleBrush, Bounds);
        }

        /// <summary>
        /// Draw a LaaR
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawLaaR(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            Point CenterBounds = CenterRect(Bounds);
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                if (Orientation == enumOrientations.Up)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1);
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top, Bounds.Left, CenterBounds.Y));
                    g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Down)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, Bounds.Top, CenterBounds.X, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1, Bounds.Left, CenterBounds.Y));
                    g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Left)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Bottom - 1, 0, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                    g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Right)
                {
                    g.DrawLine(ThisPen, Bounds.Left, CenterBounds.Y, CenterBounds.X, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Bottom - 1, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                    g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
                {
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, Bounds.Top));
                    g.DrawLine(ThisPen, CenterBounds.X / 2, Bounds.Top, CenterBounds.X / 2, Bounds.Bottom - 1);
                    g.DrawLine(ThisPen, (CenterBounds.X / 2) + CenterBounds.X, Bounds.Top, (CenterBounds.X / 2) + CenterBounds.X, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Vertical)
                {
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Top, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Bottom - 1));
                    g.DrawLine(ThisPen, Bounds.Left, CenterBounds.Y / 2, Bounds.Right - 1, CenterBounds.Y / 2);
                    g.DrawLine(ThisPen, Bounds.Left, (CenterBounds.Y / 2) + CenterBounds.Y, Bounds.Right - 1, (CenterBounds.Y / 2) + CenterBounds.Y);
                }
        }



        /// <summary>
        /// Draw a line
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawLine(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            Point CenterBounds = CenterRect(Bounds);
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                if (Orientation == enumOrientations.Up)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1);
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top, Bounds.Left, CenterBounds.Y));
                }
                else if (Orientation == enumOrientations.Down)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, Bounds.Top, CenterBounds.X, CenterBounds.Y);
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1, Bounds.Left, CenterBounds.Y));
                }
                else if (Orientation == enumOrientations.Left)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y);
                    g.FillPolygon(ThisPen.Brush, IntToPoints(CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Bottom - 1, Bounds.Left, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                }
                else if (Orientation == enumOrientations.Right)
                {
                    g.DrawLine(ThisPen, Bounds.Left, CenterBounds.Y, CenterBounds.X, CenterBounds.Y);
                    g.FillPolygon(ThisPen.Brush, IntToPoints(CenterBounds.X, Bounds.Left, CenterBounds.X, Bounds.Bottom - 1, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                }
                else if (Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
                {
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, Bounds.Top));
                    g.DrawLine(ThisPen, Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                }
                else if (Orientation == enumOrientations.Vertical)
                {
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Top, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.FillPolygon(ThisPen.Brush, IntToPoints(Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Bottom - 1));
                    g.DrawLine(ThisPen, Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1);
                }
        }

        /// <summary>
        /// Draw a load
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawLoad(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            Point CenterBounds = CenterRect(Bounds);
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                if (Orientation == enumOrientations.Up)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1);
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top, Bounds.Left, CenterBounds.Y));
                }
                else if (Orientation == enumOrientations.Down)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, Bounds.Top, CenterBounds.X, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Bottom - 1, Bounds.Left, CenterBounds.Y));
                }
                else if (Orientation == enumOrientations.Left)
                {
                    g.DrawLine(ThisPen, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Bottom - 1, Bounds.Left, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                }
                else if (Orientation == enumOrientations.Right)
                {
                    g.DrawLine(ThisPen, Bounds.Left, CenterBounds.Y, CenterBounds.X, CenterBounds.Y);
                    g.DrawPolygon(ThisPen, IntToPoints(CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Bottom - 1, Bounds.Right - 1, CenterBounds.Y, CenterBounds.X, Bounds.Top));
                }
                else if (Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
                {
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Right - 1, Bounds.Top));
                }
                else if (Orientation == enumOrientations.Vertical)
                {
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Top, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Top));
                    g.DrawPolygon(ThisPen, IntToPoints(Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1, CenterBounds.X, CenterBounds.Y, Bounds.Left, Bounds.Bottom - 1));
                }
        }

        /// <summary>
        /// Build a path from a node out to a target element
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="TargetElement"></param>
        /// <returns></returns>
        public static GraphicsPath BuildNodePath(XmlElement Node, XmlElement TargetElement)
        {
            //First, if our target element is a TEID reference, convert it                       
            Point Center1, Center2;
            GraphicsPath OutPath = new GraphicsPath();

            //Now, go through all child nodes
            Rectangle TargetRect = MM_Serializable<Rectangle>.ConvertObject(Node.Attributes["Bounds"].Value, null);
            bool LastNode = true;
            foreach (XmlElement xChild in TargetElement.ChildNodes)
                if (xChild.Name != "Descriptor" && xChild.Name != "SecondaryDescriptor")
                {
                    Rectangle Bounds2 = MM_Serializable<Rectangle>.ConvertObject(xChild.Attributes["Bounds"].Value, null);
                    bool IsJumper = xChild.Name == "PricingVector" || (xChild.HasAttribute("IsJumper") && XmlConvert.ToBoolean(xChild.Attributes["IsJumper"].Value));
                    MM_DDL_Exporter.GetStraightLine(TargetRect, Bounds2, out Center1, out Center2, LastNode && !IsJumper, LastNode = xChild.Name == "PokePoint" && !IsJumper);
                    OutPath.AddLine(Center1, Center2);
                    OutPath.CloseFigure();
                    TargetRect = Bounds2;
                }

            //Now, draw our final line
            XmlElement TargetPhysElement = null;
            if (TargetElement.HasAttribute("rdfID"))
                TargetPhysElement = TargetElement.OwnerDocument.DocumentElement.SelectSingleNode("Elements/*[@rdfID='" + TargetElement.Attributes["rdfID"].Value + "']") as XmlElement;
            if (TargetPhysElement == null)
                TargetPhysElement = TargetElement.OwnerDocument.DocumentElement.SelectSingleNode("Elements/*[@BaseElement.TEID='" + TargetElement.Attributes["TEID"].Value + "']") as XmlElement;
            
            
            Rectangle LastRect = MM_Serializable<Rectangle>.ConvertObject(TargetPhysElement.Attributes["Bounds"].Value, null);

            MM_DDL_Exporter.GetStraightLine(TargetRect, LastRect, out Center1, out Center2, LastNode, false);
            OutPath.AddLine(Center1, Center2);
            OutPath.CloseFigure();
            return OutPath;
        }


        /// <summary>
        /// Draw a poke point/jumper
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="IsJumper"></param>
        public static void DrawPokePoint(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool IsJumper)
        {

            if (Bounds.Size == new Size(4, 4))
                return;
            Point CenterBounds = CenterRect(Bounds);

            using (Pen pn = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                if (IsJumper && (Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Left || Orientation == enumOrientations.Right || Orientation == enumOrientations.Unknown))
                {
                    int JumperSize = (int)Math.Ceiling((float)Bounds.Width / 4f);
                    //g.FillRectangle(BackBrush, Bounds.Left + JumperSize, CenterBounds.Y - 1, Bounds.Width - (JumperSize * 2), Bounds.Height - 1);
                    g.DrawArc(pn, Bounds.Left + JumperSize, Bounds.Top + 1, Bounds.Width - (JumperSize * 2), Bounds.Height - 2, 0, 180);
                    g.DrawLine(pn, Bounds.Left, CenterBounds.Y, Bounds.Left + JumperSize, CenterBounds.Y);
                    g.DrawLine(pn, Bounds.Right + 1 - JumperSize, CenterBounds.Y, Bounds.Right - 1, CenterBounds.Y);
                }
                else if (IsJumper && (Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Up || Orientation == enumOrientations.Down))
                {
                    int JumperSize = (int)Math.Ceiling((float)Bounds.Height / 4f);
                    //g.FillRectangle(BackBrush, Bounds.Left, Bounds.Top + JumperSize, Bounds.Width - 1, Bounds.Height - (JumperSize * 2));
                    g.DrawArc(pn, Bounds.Left, Bounds.Top + JumperSize, Bounds.Width - 1, Bounds.Height - (JumperSize * 2), 90, 180);
                    g.DrawLine(pn, CenterBounds.X, Bounds.Top, CenterBounds.X, Bounds.Top + JumperSize);
                    g.DrawLine(pn, CenterBounds.X, Bounds.Bottom + 1 - JumperSize, CenterBounds.X, Bounds.Bottom - 1);
                }
                else
                    g.FillRectangle(pn.Brush, Bounds);
        }

        /// <summary>
        /// Draw a pricing vector
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="IsPositive"></param>
        public static void DrawPricingVector(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool IsPositive)
        {
            //First, draw our rectangle
            g.FillRectangle(BackBrush, Bounds.Left, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1);
            g.DrawRectangle(KVLevel.Energized.ForePen, Bounds.Left, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1);

            //Then, draw our arrow as appropriate
            using (Pen p = (KVLevel == null ? new Pen(Color.Red, ThicknessOverride * 3f) : new Pen(KVLevel.Energized.ForeColor, ThicknessOverride * 3f)))
            {
                if (IsPositive)
                    p.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                else
                    p.StartCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;


                if (Orientation == enumOrientations.Left || Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
                    g.DrawLine(p, Bounds.Right - 3, Bounds.Top + (Bounds.Height / 2), Bounds.Left + 3, Bounds.Top + (Bounds.Height / 2));
                else if (Orientation == enumOrientations.Right)
                    g.DrawLine(p, Bounds.Left + 3, Bounds.Top + (Bounds.Height / 2), Bounds.Right - 3, Bounds.Top + (Bounds.Height / 2));
                else if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical)
                    g.DrawLine(p, Bounds.Left + (Bounds.Width / 2), Bounds.Bottom - 3, Bounds.Left + (Bounds.Width / 2), Bounds.Top + 3);
                else if (Orientation == enumOrientations.Down)
                    g.DrawLine(p, Bounds.Left + (Bounds.Width / 2), Bounds.Top + 3, Bounds.Left + (Bounds.Width / 2), Bounds.Bottom - 3);
            }
        }

        /// <summary>
        /// Draw a resistor
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="GroundBar"></param>
        public static void DrawResistor(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool GroundBar)
        {
            Point CenterPt = CenterRect(Bounds);

            Point DeltaPt = new Point(Bounds.Width / 6, Bounds.Height / 6);
            List<Point> OutPoints = new List<Point>();
            int Cur = 0;
            if (Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Unknown || Orientation == enumOrientations.Up || Orientation == enumOrientations.Down)
            {
                OutPoints.Add(new Point(CenterPt.X, Bounds.Top));
                for (int a = Bounds.Top + 4; a < Bounds.Bottom - 3; a += 2)
                {
                    if (Cur == 0)
                        OutPoints.Add(new Point(CenterPt.X, a));
                    else if (Cur == 1)
                        OutPoints.Add(new Point(CenterPt.X - DeltaPt.X, a));
                    else
                        OutPoints.Add(new Point(CenterPt.X + DeltaPt.X, a));
                    Cur = (Cur + 1) % 3;
                }
                OutPoints.Add(new Point(CenterPt.X, Bounds.Bottom - 1));

            }
            else
            {
                OutPoints.Add(new Point(Bounds.Left, CenterPt.Y));
                for (int a = Bounds.Left + 4; a < Bounds.Right - 3; a += 2)
                {
                    if (Cur == 0)
                        OutPoints.Add(new Point(a, CenterPt.Y));
                    else if (Cur == 1)
                        OutPoints.Add(new Point(a, CenterPt.Y - DeltaPt.Y));
                    else
                        OutPoints.Add(new Point(a, CenterPt.Y + DeltaPt.Y));
                    Cur = (Cur + 1) % 3;
                }
                OutPoints.Add(new Point(Bounds.Right - 1, CenterPt.Y));
            }
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                g.DrawLines(ThisPen, OutPoints.ToArray());
            if (GroundBar)
                DrawGroundBar(g, Bounds, BackBrush, Orientation, KVLevel);

        }

        /// <summary>
        /// Draw a reactor
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="GroundBar"></param>
        public static void DrawReactor(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool GroundBar)
        {
            Point[] OutPoints = IntToPoints(0, 12, 1, 12, 2, 13, 3, 15, 4, 18, 5, 20, 6, 22, 7, 23, 8, 24, 10, 24, 12, 23, 14, 21, 15, 19, 16, 16, 17, 12, 17, 7, 16, 4, 15, 2, 12, 0, 10, 0, 8, 1, 6, 3, 5, 6, 5, 11, 7, 17, 8, 19, 10, 22, 11, 23, 13, 24, 15, 24, 16, 24, 18, 23, 19, 22, 21, 19, 22, 16, 23, 12, 23, 7, 22, 4, 21, 2, 18, 0, 16, 0, 14, 1, 13, 2, 12, 3, 11, 5, 10, 8, 10, 12, 11, 15, 13, 19, 15, 22, 18, 24, 20, 24, 22, 23, 23, 22, 25, 19, 26, 16, 27, 13, 28, 12, 30, 12, 31, 12);
            for (int a = 0; a < OutPoints.Length; a++)
                if (Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Up || Orientation == enumOrientations.Down)
                    OutPoints[a] = new Point(OutPoints[a].Y + Bounds.Left, OutPoints[a].X + Bounds.Top);
                else
                    OutPoints[a] = new Point(OutPoints[a].X + Bounds.Left, OutPoints[a].Y + Bounds.Top);
            //using (SolidBrush BackBrush = new SolidBrush(BackColor))
            //    g.FillRectangle(BackBrush, Bounds);
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                g.DrawLines(ThisPen, OutPoints);
            if (GroundBar)
                DrawGroundBar(g, Bounds, BackBrush, Orientation, KVLevel);

        }

        /// <summary>
        /// Draw a resistor/reactor hybrid
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawResistorReactor(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Down || Orientation == enumOrientations.Unknown)
            {
                DrawReactor(g, new Rectangle(Bounds.Left, Bounds.Top, Bounds.Width, Bounds.Height / 2), BackBrush, Orientation, KVLevel,false);
                DrawResistor(g, new Rectangle(Bounds.Left, Bounds.Top + (Bounds.Height / 2), Bounds.Width, Bounds.Height / 2), BackBrush, Orientation, KVLevel,false);
            }
            else
            {
                DrawReactor(g, new Rectangle(Bounds.Left, Bounds.Top, Bounds.Width, Bounds.Height), BackBrush, Orientation, KVLevel,false);
                DrawResistor(g, new Rectangle(Bounds.Left + (Bounds.Width / 2), Bounds.Top, Bounds.Width / 2, Bounds.Height), BackBrush, Orientation, KVLevel,false);
            }
            DrawGroundBar(g, Bounds, BackBrush, Orientation, KVLevel);
        }

        /// <summary>
        /// Draw a resistor/reactor hybrid
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawResistorCapacitor(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical || Orientation == enumOrientations.Down || Orientation == enumOrientations.Unknown)
            {
                DrawCapacitor(g, new Rectangle(Bounds.Left, Bounds.Top, Bounds.Width, Bounds.Height / 2), BackBrush, Orientation, KVLevel,false);
                DrawResistor(g, new Rectangle(Bounds.Left, Bounds.Top + (Bounds.Height / 2), Bounds.Width, Bounds.Height / 2), BackBrush, Orientation, KVLevel,false);
            }
            else
            {
                DrawCapacitor(g, new Rectangle(Bounds.Left, Bounds.Top, Bounds.Width, Bounds.Height), BackBrush, Orientation, KVLevel,false);
                DrawResistor(g, new Rectangle(Bounds.Left + (Bounds.Width / 2), Bounds.Top, Bounds.Width / 2, Bounds.Height), BackBrush, Orientation, KVLevel,false);
            }
            DrawGroundBar(g, Bounds, BackBrush, Orientation, KVLevel);
        }

            /// <summary>
        /// Draw a ground bar
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawGroundBar(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            //Draw our ground bar
            Point Center = CenterRect(Bounds);
            if (Orientation == enumOrientations.Up)
            {
                g.DrawLine(KVLevel.Energized.ForePen, Center.X, Center.Y, Center.X, Center.Y + 5);

            }
            else if (Orientation == enumOrientations.Down)
            {
                g.DrawLine(KVLevel.Energized.ForePen, Center.X, Center.Y, Center.X, Center.Y + 5);
                int HalfWidth = Bounds.Width / 2;
                for (int a = 2; a < 5; a++)
                    g.DrawLine(KVLevel.Energized.ForePen, Center.X - HalfWidth + (a*2), Center.Y + (a*3)-1, Center.X + HalfWidth - (a*2), Center.Y + (a*3)-1);

            }
            else if (Orientation == enumOrientations.Left)
                g.DrawLine(Pens.White, Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1);
            else if (Orientation == enumOrientations.Right)
                g.DrawLine(Pens.White, Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);

        }


        /// <summary>
        /// Draw a static var compensator
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        public static void DrawStaticVarCompensator(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel)
        {
            using (Pen DrawPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
            {
                //g.FillRectangle(Brushes.Black, this.DisplayRectangle);
                if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical)
                {
                    List<Point> OutPoint = new List<Point>();
                    foreach (Point pt in IntToPoints(18, 0, 18, 1, 16, 2, 14, 3, 12, 4, 9, 6, 8, 7, 7, 8, 6, 10, 6, 12, 7, 13, 8, 14, 10, 15, 13, 16, 16, 17, 19, 17, 22, 17, 26, 16, 28, 15, 30, 14, 31, 12, 31, 10, 30, 8, 29, 7, 28, 6, 26, 5, 23, 4, 20, 4, 17, 5, 15, 6, 13, 7, 10, 9, 8, 11, 7, 12, 6, 14, 6, 16, 8, 18, 12, 20, 16, 21, 17, 21, 20, 21, 24, 20, 27, 19, 30, 17, 31, 15, 31, 13, 30, 11, 28, 10, 26, 9, 23, 8, 21, 8, 19, 8, 17, 9, 15, 10, 13, 11, 10, 13, 8, 15, 7, 16, 6, 17, 6, 19, 7, 20, 8, 21, 9, 22, 11, 23, 13, 24, 16, 25, 18, 25, 18, 26, 18, 35))
                        OutPoint.Add(new Point(pt.X + Bounds.Left, pt.Y + Bounds.Top));
                    g.DrawLines(DrawPen, OutPoint.ToArray());
                    g.DrawLine(DrawPen, Bounds.Left + 63, Bounds.Top + 2, Bounds.Left + 63, Bounds.Top + 8);
                    g.DrawLine(DrawPen, Bounds.Left + 55, Bounds.Top + 8, Bounds.Left + 71, Bounds.Top + 8);
                    g.DrawLine(DrawPen, Bounds.Left + 63, Bounds.Top + 10, Bounds.Left + 63, Bounds.Top + 35);
                    g.DrawArc(DrawPen, Bounds.Left + 55, Bounds.Top + 8, 16, 16, 180, 180);
                    g.DrawLine(DrawPen, Bounds.Left + 18, Bounds.Top + 35, Bounds.Left + 63, Bounds.Top + 35);
                    g.DrawLine(DrawPen, Bounds.Left + (Bounds.Width / 2), Bounds.Top + 35, Bounds.Left + Bounds.Width / 2, Bounds.Bottom);
                }
                else if (Orientation == enumOrientations.Down)
                {
                    List<Point> OutPoint = new List<Point>();
                    foreach (Point pt in IntToPoints(62, 36, 62, 42, 60, 43, 58, 44, 56, 45, 53, 47, 52, 48, 51, 49, 50, 51, 50, 53, 51, 54, 52, 55, 54, 56, 57, 57, 60, 58, 63, 58, 66, 58, 70, 57, 72, 56, 74, 55, 75, 53, 75, 51, 74, 49, 73, 48, 72, 47, 70, 46, 67, 45, 64, 45, 61, 46, 59, 47, 57, 48, 54, 50, 52, 52, 51, 53, 50, 55, 50, 57, 52, 59, 56, 61, 60, 62, 61, 62, 64, 62, 68, 61, 71, 60, 74, 58, 75, 56, 75, 54, 74, 52, 72, 51, 70, 50, 67, 49, 65, 49, 63, 49, 61, 50, 59, 51, 57, 52, 54, 54, 52, 56, 51, 57, 50, 58, 50, 60, 51, 61, 52, 62, 53, 63, 55, 64, 57, 65, 60, 66, 62, 66, 62, 67, 62, 69))
                        OutPoint.Add(new Point(pt.X + Bounds.Left, pt.Y + Bounds.Top));
                    g.DrawLines(DrawPen, OutPoint.ToArray());

                    g.DrawLine(DrawPen, Bounds.Left + 21, Bounds.Top + 36, Bounds.Left + 21, Bounds.Top + 48);
                    g.DrawLine(DrawPen, Bounds.Left + 13, Bounds.Top + 48, Bounds.Left + 29, Bounds.Top + 48);
                    g.DrawLine(DrawPen, Bounds.Left + 21, Bounds.Top + 50, Bounds.Left + 21, Bounds.Top + 66);
                    g.DrawArc(DrawPen, Bounds.Left + 13, Bounds.Top + 50, 16, 16, 180, 180);
                    g.DrawLine(DrawPen, Bounds.Left + 21, Bounds.Top + 36, Bounds.Left + 62, Bounds.Top + 36);
                    g.DrawLine(DrawPen, Bounds.Left + (Bounds.Width / 2), Bounds.Top, Bounds.Left + (Bounds.Width / 2), Bounds.Top + 36);
                }
                else if (Orientation == enumOrientations.Left || Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
                {
                    List<Point> OutPoint = new List<Point>();
                    foreach (Point pt in IntToPoints(35, 27, 40, 27, 41, 28, 42, 30, 43, 33, 44, 35, 45, 37, 46, 38, 47, 39, 49, 39, 51, 38, 53, 36, 54, 34, 55, 31, 56, 27, 56, 22, 55, 19, 54, 17, 51, 15, 49, 15, 47, 16, 45, 18, 44, 21, 44, 26, 46, 32, 47, 34, 49, 37, 50, 38, 52, 39, 54, 39, 52, 32, 57, 38, 58, 37, 60, 34, 61, 31, 62, 27, 62, 22, 61, 19, 60, 17, 57, 15, 55, 15, 53, 16, 52, 17, 51, 18, 50, 20, 49, 23, 49, 27, 50, 30, 52, 34, 54, 37, 57, 39, 59, 39, 61, 38, 62, 37, 64, 34, 65, 31, 66, 28, 67, 27, 69, 27, 71, 27))
                        OutPoint.Add(new Point(pt.X + Bounds.Left, pt.Y + Bounds.Top));
                    g.DrawLines(DrawPen, OutPoint.ToArray());

                    g.DrawLine(DrawPen, Bounds.Left + 62, Bounds.Top + 53, Bounds.Left + 56, Bounds.Top + 53);
                    g.DrawLine(DrawPen, Bounds.Left + 56, Bounds.Top + 45, Bounds.Left + 56, Bounds.Top + 61);
                    g.DrawLine(DrawPen, Bounds.Left + 54, Bounds.Top + 53, Bounds.Left + 35, Bounds.Top + 53);
                    g.DrawArc(DrawPen, Bounds.Left + 38, Bounds.Top + 45, 16, 16, 270, 180);
                    g.DrawLine(DrawPen, Bounds.Left + 35, Bounds.Top + 27, Bounds.Left + 35, Bounds.Top + 53);
                    g.DrawLine(DrawPen, Bounds.Left, Bounds.Top + (Bounds.Height / 2), Bounds.Left + 35, Bounds.Top + (Bounds.Height / 2));
                }
                else if (Orientation == enumOrientations.Right)
                {
                    List<Point> OutPoint = new List<Point>();
                    foreach (Point pt in IntToPoints(1, 18, 2, 18, 3, 19, 4, 21, 5, 24, 6, 26, 7, 28, 8, 29, 9, 30, 11, 30, 13, 29, 15, 27, 16, 25, 17, 22, 18, 18, 18, 13, 17, 10, 16, 8, 13, 6, 11, 6, 9, 7, 7, 9, 6, 12, 6, 17, 8, 23, 9, 25, 11, 28, 12, 29, 14, 30, 16, 30, 17, 30, 19, 29, 20, 28, 22, 25, 23, 22, 24, 18, 24, 13, 23, 10, 22, 8, 19, 6, 17, 6, 15, 7, 14, 8, 13, 9, 12, 11, 11, 14, 11, 18, 12, 21, 14, 25, 16, 28, 19, 30, 21, 30, 23, 29, 24, 28, 26, 25, 27, 22, 28, 19, 29, 18, 31, 18, 33, 18))
                        OutPoint.Add(new Point(pt.X + Bounds.Left, pt.Y + Bounds.Top));
                    g.DrawLines(DrawPen, OutPoint.ToArray());


                    g.DrawLine(DrawPen, Bounds.Left + 13, Bounds.Top + 58, Bounds.Left + 7, Bounds.Top + 58);
                    g.DrawLine(DrawPen, Bounds.Left + 13, Bounds.Top + 50, Bounds.Left + 13, Bounds.Top + 66);
                    g.DrawLine(DrawPen, Bounds.Left + 33, Bounds.Top + 58, Bounds.Left + 15, Bounds.Top + 58);
                    g.DrawArc(DrawPen, Bounds.Left + 15, Bounds.Top + 50, 16, 16, 90, 180);
                    g.DrawLine(DrawPen, Bounds.Left + 34, Bounds.Top + 18, Bounds.Left + 34, Bounds.Top + 58);
                    g.DrawLine(DrawPen, Bounds.Left + 34, Bounds.Top + (Bounds.Height / 2), Bounds.Right, Bounds.Top + (Bounds.Height / 2));

                }
            }
        }


        /// <summary>
        /// Draw a transformer winding
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="Visible"></param>
        /// <param name="IsPhaseShifter"></param>
        public static void DrawTransformerWinding(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, bool Visible, bool IsPhaseShifter)
        {
            if (!Visible)
                return;
            using (Pen ThisPen = KVLevel != null ? new Pen(KVLevel.Energized.ForeColor, ThicknessOverride) : new Pen(Color.Red, ThicknessOverride))
                if (IsPhaseShifter)
                {
                    Point Center = MM_OneLine_Element.CenterRect(Bounds);
                    g.DrawEllipse(ThisPen, Center.X - 5, Center.Y - 5, 10, 10);
                    using (Pen NewPen = new Pen(ThisPen.Color))
                    {
                        NewPen.EndCap = LineCap.ArrowAnchor;
                        if (Orientation == enumOrientations.Up)
                            g.DrawLine(NewPen, Bounds.Left, Bounds.Bottom, Bounds.Right, Bounds.Top);
                        else if (Orientation == enumOrientations.Right)
                            g.DrawLine(NewPen, Bounds.Left, Bounds.Top, Bounds.Right, Bounds.Bottom);
                        else if (Orientation == enumOrientations.Left)
                            g.DrawLine(NewPen, Bounds.Right, Bounds.Bottom, Bounds.Left, Bounds.Top);
                        else
                            g.DrawLine(NewPen, Bounds.Right, Bounds.Top, Bounds.Left, Bounds.Bottom);
                    }
                }
                else
                    for (int a = 0; a <= 24; a += 6)
                        if (Orientation == enumOrientations.Down)
                        {
                            g.DrawLine(ThisPen, a + Bounds.Left, 3 + Bounds.Top, a + Bounds.Left, (a == 12 ? 12 : 9) + Bounds.Top);
                            if (a <= 18)
                                g.DrawArc(ThisPen, a + Bounds.Left, Bounds.Top, 6, 6, 180, 180);
                        }
                        else if (Orientation == enumOrientations.Up)
                        {
                            g.DrawLine(ThisPen, Bounds.Left + a, Bounds.Top + (a == 12 ? 0 : 3), Bounds.Left + a, Bounds.Top + 9);
                            if (a <= 18)
                                g.DrawArc(ThisPen, Bounds.Left + a, Bounds.Top + 6, 6, 6, 0, 180);
                        }
                        else if (Orientation == enumOrientations.Left)
                        {
                            g.DrawLine(ThisPen, Bounds.Left + 3, Bounds.Top + a, Bounds.Left + (a == 12 ? 12 : 9), Bounds.Top + a);
                            if (a <= 18)
                                g.DrawArc(ThisPen, Bounds.Left, Bounds.Top + a, 6, 6, 90, 180);
                        }
                        else if (Orientation == enumOrientations.Right)
                        {
                            g.DrawLine(ThisPen, Bounds.Left + (a == 12 ? 0 : 3), Bounds.Top + a, Bounds.Left + 9, Bounds.Top + a);
                            if (a <= 18)
                                g.DrawArc(ThisPen, Bounds.Left + 6, Bounds.Top + a, 6, 6, 270, 180);
                        }
        }

        /// <summary>
        /// Draw a unit
        /// </summary>
        /// <param name="g"></param>
        /// <param name="Bounds"></param>
        /// <param name="BackBrush"></param>
        /// <param name="Orientation"></param>
        /// <param name="KVLevel"></param>
        /// <param name="GenerationLevel"></param>
        public static void DrawUnit(Graphics g, Rectangle Bounds, Brush BackBrush, enumOrientations Orientation, MM_KVLevel KVLevel, float GenerationLevel)
        {
            Pen ThisPen = KVLevel == null ? Pens.Red : KVLevel.Energized.ForePen;
            Point Center = CenterRect(Bounds);
            if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Vertical)
            {
                g.DrawLine(ThisPen, Center.X - 3, Bounds.Bottom - 4, Center.X + 3, Bounds.Bottom - 4);
                g.DrawLine(ThisPen, Center.X, Center.Y, Center.X, Bounds.Bottom - 1);
                g.FillPie(BackBrush, Bounds.Left, Center.Y - Bounds.Height, Bounds.Width - 1, Bounds.Height - 1, 0, 180);
                g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Right - 1, Bounds.Top);
                g.DrawArc(ThisPen, Bounds.Left, Center.Y - Bounds.Height, Bounds.Width - 1, Bounds.Height - 1, 0, 180);
                g.FillPie(ThisPen.Brush, Bounds.Left, Center.Y - Bounds.Height, Bounds.Width - 1, Bounds.Height - 1, 0, 180f * GenerationLevel);
            }
            else if (Orientation == enumOrientations.Down)
            {
                g.DrawLine(ThisPen, Center.X - 3, Bounds.Top + 3, Center.X + 3, Bounds.Top + 3);
                g.DrawLine(ThisPen, Center.X, Bounds.Top, Center.X, Center.Y);
                g.FillPie(BackBrush, Bounds.Left, Center.Y, Bounds.Width - 1, Bounds.Height - 1, 180, 180);
                g.DrawLine(ThisPen, Bounds.Left, Bounds.Bottom - 1, Bounds.Right - 1, Bounds.Bottom - 1);
                g.DrawArc(ThisPen, Bounds.Left, Center.Y, Bounds.Width - 1, Bounds.Height - 1, 180, 180);
                g.FillPie(ThisPen.Brush, Bounds.Left, Center.Y, Bounds.Width - 1, Bounds.Height - 1, 180, 180f * GenerationLevel);

            }
            else if (Orientation == enumOrientations.Left || Orientation == enumOrientations.Horizontal || Orientation == enumOrientations.Unknown)
            {
                g.DrawLine(ThisPen, Bounds.Right - 4, Center.Y - 3, Bounds.Right - 4, Center.Y + 3);
                g.DrawLine(ThisPen, Center.X + 1, Center.Y, Bounds.Right - 1, Center.Y);
                g.FillPie(BackBrush, Center.X - Bounds.Width, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 270, 180);
                g.DrawLine(ThisPen, Bounds.Left, Bounds.Top, Bounds.Left, Bounds.Bottom - 1);
                g.DrawArc(ThisPen, Center.X - Bounds.Width, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 270, 180);
                g.FillPie(ThisPen.Brush, Center.X - Bounds.Width, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 270, 180f * GenerationLevel);
            }
            else if (Orientation == enumOrientations.Right)
            {
                g.DrawLine(ThisPen, Bounds.Left + 3, Center.Y - 3, Bounds.Left + 3, Center.Y + 3);
                g.DrawLine(ThisPen, Bounds.Left, Center.Y, Center.X, Center.Y);
                g.FillPie(BackBrush, Center.X, Bounds.Left, Bounds.Width - 1, Bounds.Height - 1, 90, 180);
                g.DrawLine(ThisPen, Bounds.Right - 1, Bounds.Top, Bounds.Right - 1, Bounds.Bottom - 1);
                g.DrawArc(ThisPen, Center.X, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 90, 180);
                g.FillPie(ThisPen.Brush, Center.X, Bounds.Top, Bounds.Width - 1, Bounds.Height - 1, 90, 180f * GenerationLevel);
            }
        }
        #endregion

        #region Variable declarations
        /// <summary>The paths from a node through poke points to the target element</summary>
        public Dictionary<MM_OneLine_Element, GraphicsPath> NodePaths;

        /// <summary>The XML definition for our element</summary>
        public XmlElement Definition;

        /// <summary>Our base element for the one-line component</summary>
        public CIM_Element CIM
        {
            get { return _CIM; }
            set
            {
                _CIM = value;
                if (_CIM == null)
                    return;
                Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("rdfID")).Value = value.rdfID.ToString();
                Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.TEID")).Value = value.TEID;
                Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.ElemType")).Value = value.ElemType;

                if (value.Owner != null)
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Owner")).Value = value.Owner.TEID;
                if (value.Operator != null)
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Operator")).Value = value.Operator.TEID;
                if (value.VoltageLevel != null)
                {
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.KVLevel")).Value = value.VoltageLevel.Name;
                    this.KVLevel = Data_Manager.LocateKVLevel(value.VoltageLevel.Name);
                }
                else
                    this.KVLevel = Data_Manager.LocateKVLevel("Other KV");
                if (value.Substation != null)
                {
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Substation")).Value = value.Substation.TEID;
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.SubName")).Value = MM_Type_Converter.TitleCase(value.Substation.Name);
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.SubLongName")).Value = MM_Type_Converter.TitleCase(value.Substation.LongName);
                }

                if (value.ElemType == "Breaker" || value.ElemType == "Switch")
                {
                    bool Opened = XmlConvert.ToBoolean(value["cim:Switch.normalOpen"]);
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("Opened")).Value = Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("ScadaOpened")).Value = Opened ? "Checked" : "Unchecked";
                    this.Opened = Opened ? CheckState.Checked : CheckState.Unchecked;
                }
                else if (value.ElemType == "Transformer")
                {
                    StringBuilder sB = new StringBuilder();
                    for (int a = 1; a <= value.TransformerWinding.Length; a++)
                    {
                        CIM_Element Winding = value.TransformerWinding[a - 1];
                        Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.KVLevel" + a.ToString())).Value = Winding.VoltageLevel.Name;
                        Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Winding" + a.ToString())).Value = Winding.TEID;
                        sB.Append((sB.Length == 0 ? "" : ",") + Winding.TEID);
                    }
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Windings")).Value = sB.ToString();
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.PhaseShifter")).Value = XmlConvert.ToString(value["cim:PowerTransformer.transformerType"].IndexOf("Phase") != -1);
                }
                else if (value.ElemType == "Unit")
                {
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.IsRC")).Value = XmlConvert.ToString(value.TypeName == "cim:CombinedCyclePlant");
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.UnitType")).Value = value.ParseSingle("Unit", null).TypeName.Split(':')[1];
                }



                if (value.TypeName == "cim:ACLineSegment" || value.TypeName == "cim:SeriesCompensator")
                {
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.ConnectedStations")).Value = value.ACSegmentStations[0].TEID + "," + value.ACSegmentStations[1].TEID;
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.IsSeriesCompenstor")).Value = XmlConvert.ToString(value.TypeName == "cim:SeriesCompensator");
                    CIM_Element LineElem = value.ParseSingle("cim:Line", null);

                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.IsMultipleSegment")).Value = XmlConvert.ToString(LineElem.InLinks.Length > 1);
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.LineTEID")).Value = value.ParseSingle("cim:Line", null).TEID;
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.LongName")).Value = value["cim:IdentifiedObject.description"];
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Name")).Value = MM_Type_Converter.TitleCase(LineElem.InLinks.Length == 1 ? LineElem.Name : LineElem.Name + value.Name);
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.FromSubstation")).Value = value.ACSegmentStations[0].TEID;
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.ToSubstation")).Value = value.ACSegmentStations[1].TEID;
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Length")).Value = value["cim:Conductor.length"];

                }
                else
                    Definition.Attributes.Append(Definition.OwnerDocument.CreateAttribute("BaseElement.Name")).Value = MM_Type_Converter.TitleCase(value.Name);
            }
        }
        private CIM_Element _CIM;

        /// <summary>The substation or contingency definition in which our element is located</summary>
        public CIM_Element OwnerElement;

        /// <summary>Our collection of export points on labels</summary>
        public MM_OneLine_Value[] ExportValues
        {
            get { return _ExportValues; }
            set { _ExportValues = value; }
        }
        private MM_OneLine_Value[] _ExportValues;

        /// <summary>
        /// Report the outer bounds of an element
        /// </summary>
        public Rectangle OuterBounds
        {
            get
            {
                if (ExportValues == null)
                    return this.Bounds;
                Rectangle OutRect = this.Bounds;
                foreach (MM_OneLine_Value Val in this.ExportValues)
                    OutRect = Rectangle.Union(OutRect, Val.Bounds);
                return OutRect;
            }
        }


        /// <summary>
        /// Make sure our text is visible
        /// </summary>
        [Category("Layout"), Description("The text of our label"), Browsable(true)]
        public override String Text
        {
            get { return base.Text; }
            set
            {
                MM_Serializable.WriteAttribute(Definition, "Text", value);
                Rectangle PreBounds = this.Bounds;
                base.Text = value;
                if (this.Bounds != PreBounds)
                    Console.WriteLine("hmm...");
                this.Font = Font;
            }
        }

        /// <summary>
        /// Make sure our font is visible
        /// </summary>
        [Category("Layout"), Description("The font of our display"), Browsable(true)]
        public override Font Font
        {
            get { return base.Font; }
            set
            {
                if (this.ElemType == enumElemTypes.Descriptor || this.ElemType == enumElemTypes.SecondaryDescriptor || this.ElemType == enumElemTypes.Label)
                {
                    Rectangle PreBounds = this.Bounds;
                    base.Font = value;
                    MM_Serializable.WriteAttribute(Definition, "Font", value);
                    this.Location = PreBounds.Location;
                }
            }
        }

        /// <summary>
        /// The foreground color of our display
        /// </summary>
        [Category("Layout"), Description("The foreground color of our display"), Browsable(true)]
        public override Color ForeColor
        {
            get { return base.ForeColor; }
            set
            {
                MM_Serializable.WriteAttribute(Definition, "ForeColor", value);
                base.ForeColor = value;
            }
        }

        /// <summary>
        /// The background color of our display
        /// </summary>
        [Category("Layout"), Description("The background color of our display"), Browsable(true)]
        public override Color BackColor
        {
            get { return base.BackColor; }
            set
            {
                base.BackColor = value;
                MM_Serializable.WriteAttribute(Definition, "BackColor", value);
            }
        }

        /// <summary>The orientation of our element</summary>
        [Category("Layout"), Description("The orientation of our element"), Browsable(true)]
        public enumOrientations Orientation
        {
            get { return _Orientation; }
            set
            {
                _Orientation = value;

                //If initializing, do nothing
                if (this.Parent != null)
                    ChangeOrientation(value);
            }
        }



        /// <summary>
        /// Explicitly change our orientation
        /// </summary>
        /// <param name="Orientation"></param>
        public void ChangeOrientation(enumOrientations Orientation)
        {
            MM_Serializable.WriteAttribute(Definition, "Orientation", Orientation);
            if (ElemType == enumElemTypes.Breaker)
                UpdateSize(26, 26, enumOrientations.Horizontal);
            else if (ElemType == enumElemTypes.Switch)
                UpdateSize(26, 26, enumOrientations.Horizontal);
            else if (ElemType == enumElemTypes.Unit)
                UpdateSize(26, 26, enumOrientations.Left);
            else if (ElemType == enumElemTypes.Node)
                if (IsJumper)
                    UpdateSize(11, 35, enumOrientations.Vertical);
                else if (!IsVisible)
                    UpdateSize(4, 4, enumOrientations.Left);
                else if (CIM.ParseSingle("cim:Terminal>BusbarSection", null) != null)
                    if (this.Width == this.Height)
                        UpdateSize(8, 100, enumOrientations.Vertical);
                    else
                        UpdateSize(Math.Max(this.Width, this.Height), Math.Min(this.Width, this.Height), enumOrientations.Vertical);
                else
                    UpdateSize(8, 8, enumOrientations.Left);

            else if (ElemType == enumElemTypes.Transformer)
            {
                UpdateSize(26, 25, enumOrientations.Horizontal);
                Point CenterXF = CenterRect(DisplayRectangle);
                if (Windings != null)
                    for (int a = 0; a < Windings.Length; a++)
                        if (Windings[a] != null)
                            if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Down || Orientation == enumOrientations.Vertical)
                            {
                                Windings[a].Bounds = new Rectangle(0, (a == 0 ? 0 : CenterXF.Y), Width, CenterXF.Y);
                                Windings[a].Orientation = a == 0 ? enumOrientations.Up : enumOrientations.Down;
                                MM_Serializable.WriteAttribute(Windings[a].Definition, "Orientation", Windings[a].Orientation);
                            }
                            else
                            {
                                Windings[a].Bounds = new Rectangle((a == 0 ? 0 : CenterXF.X), 0, CenterXF.X, Height);
                                Windings[a].Orientation = a == 1 ? enumOrientations.Left : enumOrientations.Right;
                                MM_Serializable.WriteAttribute(Windings[a].Definition, "Orientation", Windings[a].Orientation);
                            }
            }
            else if (ElemType == enumElemTypes.PricingVector)
                UpdateSize(30, 15, enumOrientations.Left);
            else if (ElemType == enumElemTypes.PokePoint)
                if (IsJumper)
                    UpdateSize(35, 11, enumOrientations.Left);
                else if (IsVisible)
                    UpdateSize(8, 8, enumOrientations.Left);
                else
                    UpdateSize(4, 4, enumOrientations.Left);
            else if (ElemType == enumElemTypes.Line)
                UpdateSize(23, 15, enumOrientations.Left);
            else if (ElemType == enumElemTypes.Load)
                UpdateSize(23, 15, enumOrientations.Left);
            else if (ElemType == enumElemTypes.LAAR)
                UpdateSize(23, 15, enumOrientations.Left);
            else if (ElemType == enumElemTypes.Reactor)
                UpdateSize(32, 25, enumOrientations.Left);
            else if (ElemType == enumElemTypes.ResistorReactor)
                UpdateSize(32 * 2, 25, enumOrientations.Left);
            else if (ElemType == enumElemTypes.ResistorCapacitor)
                UpdateSize(32 * 2, 25, enumOrientations.Left);
            else if (ElemType == enumElemTypes.Capacitor)
                UpdateSize(24, 20, enumOrientations.Left);
            else if (ElemType == enumElemTypes.EndCap)
                UpdateSize(7, 7, enumOrientations.Left);
            else if (ElemType == enumElemTypes.StaticVarCompensator)
                UpdateSize(70, 77, enumOrientations.Left);
        }

        /// <summary>
        /// Update the size of the element based on its orientation
        /// </summary>
        /// <param name="Width">The width of the element if it's horizontal</param>
        /// <param name="Height">The height of the element if it's horizontal</param>
        /// <param name="DefaultOrientation">The default orientation</param>
        public void UpdateSize(int Width, int Height, enumOrientations DefaultOrientation)
        {


            if (Orientation == enumOrientations.Unknown)
            {} //Orientation = DefaultOrientation;
            else if (Orientation == enumOrientations.Up || Orientation == enumOrientations.Down || Orientation == enumOrientations.Vertical)
                this.Size = new Size(Height, Width);
            else
                this.Size = new Size(Width, Height);

            //If we're initializing, don't do anything yet
            if (this.Location != Point.Empty)
                MM_Serializable.WriteAttribute(Definition, "Bounds", Bounds);

        }

        /// <summary>
        /// When our size changes, make sure everything's ok
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            //this.Orientation = Orientation;
            base.OnSizeChanged(e);
        }

        /// <summary>
        /// Report the center of our element
        /// </summary>
        public Point Center
        {
            get { return new Point(CenterX, CenterY); }
            set
            {
                CenterX = value.X;
                CenterY = value.Y;
            }
        }

        /// <summary>
        /// Report the horizontal center of our element
        /// </summary>
        public int CenterX
        {
            get { return this.Left + (this.Width / 2); }
            set { this.Left = value - (this.Width / 2); }
        }

        /// <summary>
        /// Report the vertical center of our element
        /// </summary>
        public int CenterY
        {
            get { return this.Top + (this.Height / 2); }
            set { this.Top = value - (this.Height / 2); }
        }


        private enumOrientations _Orientation = enumOrientations.Unknown;

        /// <summary>The KV level of our element</summary>
        public MM_KVLevel KVLevel;

        /// <summary>Our element's descriptor</summary>
        public MM_OneLine_Element Descriptor = null;

        /// <summary>Our element's secondary descriptor</summary>
        public MM_OneLine_Element SecondaryDescriptor = null;

        /// <summary>Whether this element is selected</summary>
        public bool Selected = false;

        /// <summary>The parent element for us</summary>
        public MM_OneLine_Element ParentElement = null;

        /// <summary>The current element type</summary>
        public enumElemTypes ElemType;

        /// <summary>If a poke point, whether this element is a jumper</summary>
        public bool IsJumper
        {
            get { return _IsJumper; }
            set
            {
                _IsJumper = value;
                MM_Serializable.WriteAttribute(Definition, "IsJumper", value);
                Orientation = Orientation;
            }
        }
        private bool _IsJumper = false;

        /// <summary>If a poke point, whether this element is visible</summary>
        [Category("NMMS"), Description("If a poke point, whether this element is visible"), DefaultValue(true)]
        public bool IsVisible
        {
            get { return _IsVisible; }
            set
            {
                _IsVisible = value;
                MM_Serializable.WriteAttribute(Definition, "IsVisible", value);
                Orientation = Orientation;
            }
        }
        private bool _IsVisible = true;


        /// <summary>Whether a descriptor arrow should be drawn</summary>
        [Category("NMMS"), Description("Whether a descriptor arrow should be drawn")]
        public bool DescriptorArrow
        {
            get { return _DescriptorArrow; }
            set
            {
                _DescriptorArrow = value;
                MM_Serializable.WriteAttribute(Definition, "DescriptorArrow", value);
            }
        }
        private bool _DescriptorArrow = false;


        /// <summary>If a pricing vector, whether flow is towards the node</summary>
        [Category("NMMS"), Description("If a pricing vector, whether flow is towards the node")]
        public bool IsPositive
        {
            get { return _IsPositive; }
            set
            {
                _IsPositive = value;
                MM_Serializable.WriteAttribute(Definition, "IsPositive", value);
            }
        }
        private bool _IsPositive = false;

        /// <summary>If a switch or breaker, the state of the element</summary>
        [Category("NMMS"), Description("If a switch or breaker, the state of the element")]
        public CheckState Opened
        {
            get { return _Opened; }
            set
            {
                _Opened = value;
                MM_Serializable.WriteAttribute(Definition, "Opened", value);
            }
        }
        private CheckState _Opened = CheckState.Indeterminate;

        /// <summary>Our collection of windings</summary>
        [Category("NMMS"), Description("Our collection of windings")]
        public MM_OneLine_TransformerWinding[] Windings
        {
            get { return _Windings; }
            set { _Windings = value; }
        }
        private MM_OneLine_TransformerWinding[] _Windings;

        /// <summary>
        /// The image to be displayed, if selected
        /// </summary>
        public Image Image
        {
            get { return _Image; }
            set
            {
                _Image = value;
                using (System.Drawing.Bitmap b = new Bitmap(value))
                using (MemoryStream mS = new MemoryStream())
                {
                    b.Save(mS, ImageFormat.Jpeg);
                    MM_Serializable.WriteAttribute(Definition, "Image", Convert.ToBase64String(mS.ToArray()));
                }
            }
        }

        private Image _Image;
        #endregion

        #region Properties
        /// <summary>
        /// Determine if this element can be sized
        /// </summary>
        public bool CanSize
        {
            get
            {
                return this.ElemType == enumElemTypes.Image || this.ElemType == enumElemTypes.Label || this.ElemType == enumElemTypes.Circle || this.ElemType == enumElemTypes.Rectangle || this.ElemType == enumElemTypes.ArrowLine || (this.ElemType == enumElemTypes.Node && Descriptor != null);
            }
        }
        #endregion

        #region Initializations
        /// <summary>
        /// Create a new MM element from its CIM base against a model
        /// </summary>
        /// <param name="BaseElement"></param>
        /// <param name="OneLineBase"></param>
        /// <param name="BaseDocument"></param>
        public MM_OneLine_Element(CIM_Element BaseElement, CIM_Element OneLineBase, XmlDocument BaseDocument)
        {
            this.InitializeComponent();
            this.AutoSize = false;
            Definition = BaseDocument.CreateElement(BaseElement.ElemType);
            this.ElemType = (enumElemTypes)Enum.Parse(typeof(enumElemTypes), Definition.Name);
            Definition.Attributes.Append(BaseDocument.CreateAttribute("IsVisible")).Value = "true";
            Definition.Attributes.Append(BaseDocument.CreateAttribute("Bounds")).Value = "1,1,50,50";
            this.CIM = BaseElement;


            //Add descriptor and resource node names as needed, and size them
            using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
            {
                if (BaseElement.TypeName != "cim:ConnectivityNode" || BaseElement.ParseSingle("cim:Terminal>cim:BusbarSection", null) != null)
                {
                    XmlElement Desc = Definition.AppendChild(BaseDocument.CreateElement("Descriptor")) as XmlElement;
                    String LabelText = MM_OneLine_Element.DescriptorText(BaseElement, null, false);
                    Size EstSize = Size.Ceiling(g.MeasureString(LabelText, SystemFonts.CaptionFont));
                    Desc.Attributes.Append(BaseDocument.CreateAttribute("DescriptorText")).Value = LabelText;
                    Desc.Attributes.Append(BaseDocument.CreateAttribute("Bounds")).Value = Width.ToString() + ",1," + EstSize.Width.ToString() + "," + EstSize.Height.ToString();

                    Rectangle LabelBounds = new Rectangle(this.Right + 5, this.Top, EstSize.Width, EstSize.Height);
                    foreach (MM_OneLine_Value Val in BuildExportPointsWithLocations(Desc, BuildExportPoints(BaseElement, OneLineBase, false, Desc), this.Bounds, LabelBounds))
                        LabelBounds = Rectangle.Union(LabelBounds, Val.Bounds);
                    Desc.Attributes.Append(BaseDocument.CreateAttribute("LabelBounds")).Value = String.Format("{0},{1},{2},{3}", LabelBounds.Left, LabelBounds.Top, LabelBounds.Width, LabelBounds.Height);


                }
                if (BaseElement.TypeName == "cim:ConnectivityNode" && BaseElement.ParseSingle("etx:ElectricalBus<etx:ResourceNode", null) != null)
                {
                    XmlElement sDesc = Definition.AppendChild(BaseDocument.CreateElement("SecondaryDescriptor")) as XmlElement;
                    String LabelText = MM_OneLine_Element.DescriptorText(BaseElement, null, true);
                    Size EstSize = Size.Ceiling(g.MeasureString(LabelText, SystemFonts.CaptionFont));
                    sDesc.Attributes.Append(BaseDocument.CreateAttribute("Bounds")).Value = Width.ToString() + ",1," + EstSize.Width.ToString() + "," + EstSize.Height.ToString();
                    sDesc.Attributes.Append(BaseDocument.CreateAttribute("DescriptorText")).Value = LabelText;
                }
            }


            //If a transformer winding, add in our sub-elements
            if (BaseElement.TypeName == "cim:PowerTransformer")
            {
                List<MM_OneLine_TransformerWinding> Windings = new List<MM_OneLine_TransformerWinding>();
                foreach (CIM_Element Winding in BaseElement.TransformerWinding)
                {
                    XmlElement xWinding = Definition.AppendChild(BaseDocument.CreateElement("Winding")) as XmlElement;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.ElemType")).Value = "TransformerWinding";
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.TEID")).Value = Winding.TEID;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.KVLevel")).Value = Winding.VoltageLevel.Name;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Name")).Value = Winding.Name;
                    if (Winding.Owner == null)
                        if (BaseElement.Owner != null)
                            xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Owner")).Value = BaseElement.Owner.TEID;
                        else
                            xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Owner")).Value = BaseElement.Substation.TEID;
                    else
                        xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Owner")).Value = Winding.Owner.TEID;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Operator")).Value = Winding.Operator.TEID;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Substation")).Value = Winding.Substation.TEID;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.SubName")).Value = Winding.Substation.Name;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.SubLongName")).Value = Winding.Substation.LongName;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.Transformer")).Value = BaseElement.TEID;
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.IsPrimary")).Value = XmlConvert.ToString(Winding.Attributes["cim:TransformerWinding.windingType"].EndsWith("primary"));

                    CIM_Element AssociatedNode = Winding.ParseSingle("cim:Terminal>cim:ConnectivityNode", CIM.CIM);
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.AssociatedNodeName")).Value = AssociatedNode.Name; 
                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("BaseElement.AssociatedNode")).Value = AssociatedNode.TEID;



                    xWinding.Attributes.Append(BaseDocument.CreateAttribute("rdfID")).Value = Winding.rdfID.ToString();
                    Windings.Add(new MM_OneLine_TransformerWinding(xWinding, BaseElement.CIM));
                }
                this.Windings = Windings.ToArray();
            }
            else if (BaseElement.TypeName == "etx:PricingVector")
            {
                CIM_Element EPSMeter = BaseElement.ParseSingle("etx:EPSMeter", null);
                Definition.Attributes.Append(BaseDocument.CreateAttribute("IsPositive")).Value = BaseElement["etx:PricingVector.positiveFlowIn"];
                Definition.Attributes.Append(BaseDocument.CreateAttribute("EPSMeter.TEID")).Value = EPSMeter.TEID;
                Definition.Attributes.Append(BaseDocument.CreateAttribute("EPSMeter.RID")).Value = EPSMeter["etx:EPSMeter.RID"];
            }

            MM_Serializable.InitializeFromXml(this, Definition, null);

            //Set our default orientation
            if (!CanSize || ElemType == enumElemTypes.Breaker || ElemType == enumElemTypes.Switch || ElemType == enumElemTypes.Transformer)
            {
                Orientation = enumOrientations.Vertical;
                ChangeOrientation(Orientation);
            }
            else
            {
                Orientation = enumOrientations.Down;
                ChangeOrientation(Orientation);
            }

            //If we have a descriptor, update our bounds
            if (Definition["Descriptor"] != null)
            {
                Rectangle TargetRect = MM_Serializable<Rectangle>.ConvertObject(Definition["Descriptor"].Attributes["Bounds"].Value, null);
                foreach (MM_OneLine_Value Val in BuildExportPointsWithLocations(Definition, BuildExportPoints(BaseElement, OneLineBase, false, Definition["Descriptor"]), this.Bounds, TargetRect))
                    TargetRect = Rectangle.Union(TargetRect, Val.Bounds);
                Definition["Descriptor"].Attributes["Bounds"].Value = String.Format("{0},{1},{2},{3}", TargetRect.Left, TargetRect.Top, TargetRect.Width, TargetRect.Height);
            }
        }

        /// <summary>
        /// Initialize a new element directly from CIM
        /// </summary>
        /// <param name="Element"></param>
        /// <param name="xElem"></param>
        public MM_OneLine_Element(CIM_Element Element, XmlElement xElem)
        {
            this.InitializeComponent();
            this.AutoSize = false;
            this.ElemType = (enumElemTypes)Enum.Parse(typeof(enumElemTypes), Element.ElemType);
            this.Definition = xElem;
            this.CIM = Element;
            MM_Serializable.InitializeFromXml(this, xElem, Element.CIM);
            if (this.ElemType == enumElemTypes.Line || this.ElemType == enumElemTypes.Node || this.ElemType == enumElemTypes.Transformer)
                this.ChangeOrientation(enumOrientations.Vertical);
            else
                this.ChangeOrientation(enumOrientations.Up);
        }


        /// <summary>
        /// Intialize a new one-line element
        /// </summary>
        /// <param name="CIM"></param>
        /// <param name="BaseElement"></param>
        /// <param name="OneLine"></param>
        public MM_OneLine_Element(XmlElement OneLine, MM_Database_Model CIM, CIM_Element BaseElement)
        {
            InitializeComponent();
            this.AutoSize = false;
            this.OwnerElement = BaseElement;
            if (OneLine.Name == "UnlinkedElement")
                this.ElemType = (enumElemTypes)Enum.Parse(typeof(enumElemTypes), OneLine.Attributes["ElemType"].Value);
            else
                this.ElemType = (enumElemTypes)Enum.Parse(typeof(enumElemTypes), OneLine.Name);
            this.Definition = OneLine;


            if (OneLine.Name.EndsWith("Descriptor"))
            {
                XmlNode xParent = OneLine.ParentNode;
                while (xParent.Attributes["rdfID"] == null)
                    xParent = xParent.ParentNode;
                this.CIM = CIM.FromRdfID(xParent.Attributes["rdfID"].Value);
                if (!OneLine.HasAttribute("Font"))
                    this.Font = new Font("Arial", 8, OneLine.Name == "SecondaryDescriptor" ? FontStyle.Italic : FontStyle.Regular);
            }
            else if (OneLine.HasAttribute("rdfID"))
                this.CIM = CIM.FromRdfID(OneLine.Attributes["rdfID"].Value);
            else if (OneLine.HasAttribute("BaseElement.TEID"))
            {
                this.CIM = CIM.FromTEID(Convert.ToUInt64(OneLine.Attributes["BaseElement.TEID"].Value));

                //Add in our rdf:ID
                if (this.CIM != null)
                    MM_Serializable.WriteAttribute(OneLine, "rdfID", this.CIM.rdfID);
            }



            MM_Serializable.InitializeFromXml(this, OneLine, CIM);
            if (this.CIM != null)
                this.KVLevel = Data_Manager.LocateKVLevel(this.CIM.VoltageLevel);

            //If we're a transformer, pull in the collection of windings
            if (this.ElemType == enumElemTypes.Transformer)
            {
                List<MM_OneLine_TransformerWinding> Windings = new List<MM_OneLine_TransformerWinding>();
                foreach (XmlElement xWinding in Definition.ChildNodes)
                    if (xWinding.Name == "Winding")
                        Windings.Add(new MM_OneLine_TransformerWinding(xWinding, CIM));
                this.Windings = Windings.ToArray();
            }

            //Determine our text for this element
            if (this.CIM != null)
                this.Text = MM_OneLine_Element.DescriptorText(this.CIM, BaseElement, ElemType == enumElemTypes.SecondaryDescriptor);
            if (this.ElemType == enumElemTypes.Descriptor || this.ElemType == enumElemTypes.SecondaryDescriptor)
                using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
                    this.Size = Size.Ceiling(g.MeasureString(Text, this.Font));
        }

        /// <summary>
        /// Rebuild our node path
        /// </summary>
        /// <param name="Elem"></param>
        /// <param name="TargetElement"></param>
        public GraphicsPath RebuildNodePath(MM_OneLine_Element Elem, XmlElement TargetElement)
        {
            GraphicsPath TargetPath = MM_OneLine_Element.BuildNodePath(Definition, TargetElement);
            if (NodePaths == null)
                NodePaths = new Dictionary<MM_OneLine_Element, GraphicsPath>(Definition.ChildNodes.Count);
            if (NodePaths.ContainsKey(Elem))
            {
                NodePaths[Elem].Dispose();
                NodePaths[Elem] = TargetPath;
            }
            else
                NodePaths.Add(Elem, TargetPath);
            return TargetPath;
        }
        #endregion

        #region Rendering
        /// <summary>
        /// Override painting of the background
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (this.CIM == null && this.ElemType != enumElemTypes.Label && this.ElemType != enumElemTypes.Circle && this.ElemType != enumElemTypes.Rectangle && this.ElemType != enumElemTypes.Image && this.ElemType != enumElemTypes.ArrowLine)
                e.Graphics.FillRectangle(Brushes.DarkRed, e.ClipRectangle);
            else
                base.OnPaintBackground(e);
        }
        /// <summary>
        /// Handle the rendering of our one-line element
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            if (ElemType == enumElemTypes.Transformer)
                foreach (MM_OneLine_TransformerWinding Winding in Windings)
                {
                    Rectangle WindingBounds = Winding.Bounds;
                    WindingBounds.X += DisplayRectangle.Left;
                    WindingBounds.Y += DisplayRectangle.Top;
                    MM_OneLine_Element.DrawTransformerWinding(e.Graphics, Winding.Bounds, Brushes.Black, Winding.Orientation, Winding.KVLevel, Winding.Visible, Winding.IsPhaseShifter && Winding.IsPrimary);
                }
            else if (ElemType == enumElemTypes.Descriptor || ElemType == enumElemTypes.SecondaryDescriptor)
                e.Graphics.DrawString(this.Text, Font, Brushes.LightGray, DisplayRectangle, MM_OneLine_Element.CenterFormat);
            else if (ElemType == enumElemTypes.Breaker)
                MM_OneLine_Element.DrawBreaker(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel, Opened);
            else if (ElemType == enumElemTypes.Switch)
                MM_OneLine_Element.DrawSwitch(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel, Opened);
            else if (ElemType == enumElemTypes.Unit)
                MM_OneLine_Element.DrawUnit(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel, .5f);
            else if (ElemType == enumElemTypes.Line)
                MM_OneLine_Element.DrawLine(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.Reactor)
                MM_OneLine_Element.DrawReactor(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel,true);
            else if (ElemType == enumElemTypes.Load)
                MM_OneLine_Element.DrawLoad(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.LAAR)
                MM_OneLine_Element.DrawLaaR(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.EndCap)
                MM_OneLine_Element.DrawEndCap(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.Capacitor)
                MM_OneLine_Element.DrawCapacitor(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel,true);
            else if (ElemType == enumElemTypes.StaticVarCompensator)
                MM_OneLine_Element.DrawStaticVarCompensator(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.ResistorReactor)
                MM_OneLine_Element.DrawResistorReactor(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.ResistorCapacitor)
                MM_OneLine_Element.DrawResistorCapacitor(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel);
            else if (ElemType == enumElemTypes.Resistor)
                MM_OneLine_Element.DrawResistor(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel,true);
            else if (ElemType == enumElemTypes.Node || ElemType == enumElemTypes.PokePoint)
                if (IsJumper || IsVisible)
                    MM_OneLine_Element.DrawPokePoint(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel, IsJumper);
                else
                    e.Graphics.FillRectangle(KVLevel.Energized.ForePen.Brush, DisplayRectangle);
            else if (ElemType == enumElemTypes.PricingVector)
                MM_OneLine_Element.DrawPricingVector(e.Graphics, DisplayRectangle, Brushes.Black, Orientation, KVLevel, IsPositive);
            else if (ElemType == enumElemTypes.Label)
                e.Graphics.DrawString(this.Text, this.Font, Brushes.White, DisplayRectangle);
            else if (ElemType == enumElemTypes.Rectangle)
                using (Pen DrawPen = new Pen(this.ForeColor))
                    e.Graphics.DrawRectangle(DrawPen, DisplayRectangle.Left, DisplayRectangle.Top, DisplayRectangle.Width - 1, DisplayRectangle.Height - 1);
            else if (ElemType == enumElemTypes.Circle)
                using (Pen DrawPen = new Pen(this.ForeColor))
                    e.Graphics.DrawEllipse(DrawPen, DisplayRectangle.Left, DisplayRectangle.Top, DisplayRectangle.Width - 1, DisplayRectangle.Height - 1);
            else if (ElemType == enumElemTypes.ArrowLine)
                using (Pen DrawPen = new Pen(this.ForeColor))
                {
                    DrawPen.StartCap = LineCap.ArrowAnchor;
                    DrawPen.Width = 2;
                    e.Graphics.DrawLine(DrawPen, DisplayRectangle.Left, DisplayRectangle.Top, DisplayRectangle.Right, DisplayRectangle.Bottom);
                }
            else if (ElemType == enumElemTypes.Image && Image != null)
                e.Graphics.DrawImage(Image, DisplayRectangle);
        }
        #endregion

        #region Identity
        /// <summary>
        /// Report an easy-to-read identifier for our element
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (ElemType == enumElemTypes.Descriptor || ElemType == enumElemTypes.SecondaryDescriptor)
                return ElemType.ToString() + " for " + ParentElement.ToString();
            else if (ElemType == enumElemTypes.Line)
            {
                CIM_Element ParentLine = CIM.ParseSingle("cim:Line", null);
                return MM_Type_Converter.TitleCase(ParentLine.Name + (ParentLine.InLinks.Length == 1 ? "" : CIM.Name));
            }
            else
                return ElemType.ToString() + " " + MM_Type_Converter.TitleCase(CIM.Name);
        }

        /// <summary>
        /// Report the hash code for our element
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        /// <summary>
        /// Determine whether two elements are equal
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        #endregion
    }
}